5

我正在使用第 3 方库 ( clj-msgpack ),并希望为该库还为其提供处理程序的类型扩展协议。

就其本身而言,这很简单——但有什么方法可以做到这一点,不会影响在同一个 JVM 中运行的该库的其他用户?类似于动态 var 绑定的东西(仅在堆栈上的给定点下生效)将是理想的。

目前,我正在做一个无条件覆盖,但使用一个动态变量来启用我修改后的行为;然而,这让我觉得太像猴子补丁了。

出于好奇,我正在实施的(公认的可憎)如下:

(in-ns 'clj-msgpack.core)

(def ^:dynamic *keywordize-strings*
  "Assume that any string starting with a colon should be unpacked to a keyword"
  false)

(extend-protocol Unwrapable
  RawValue
  (unwrap [o]
    (let [v (.getString o)]
      (if (and *keywordize-strings* (.startsWith v ":"))
        (keyword (.substring v 1))
        v))))
4

1 回答 1

1

经过一番思考,我看到了两种基本方法(其中一种是我从你那里得到的):

动态绑定(就像您现在所做的那样):

一些人抱怨动态绑定是最令人惊讶的。“什么?只有在从那里调用时才会这样?”。虽然我个人并不认为这是一件坏事(tm),但有些人会这样做。在这种情况下,它完全符合您的愿望,只要您有一点可以决定是否需要关键字字符串,这应该可以工作。如果您添加将它们更改回来的第二个点以及穿过这两个点的代码路径......您自己的。但是,嘿,工作代码有它的优点。

遗产:

good'ol java 风格或使用 clojure 的附加层次结构,您可以将您传递的对象类型扩展为扩展 widgewhatzit 的关键字化字符串widgewhatzit 并为您的特定子类添加一个新的处理程序。这仅在某些情况下有效,并在设计的其余部分强制使用不同的对象样式。一些聪明的人也会争辩说它仍然遵循最令人惊讶的原则,因为当通过另一个代码路径调用时,对象的类型会有所不同。


就个人而言,除非您可以将整个程序更改为使用关键字而不是字符串,否则我会使用您现有的解决方案(这当然是我的第一个(可能有争议的)选择)

于 2012-10-17T21:20:48.307 回答