2012-10-17 23 views
5

我正在使用第三方库(clj-msgpack),并希望扩展该库也提供处理程序的类型的协议。扩展库提供的协议,而不会影响其他用户

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

目前,我正在做无条件覆盖,但使用动态变量来启用我的修改行为;然而,这感觉像猴子修补我的舒适太像。

对于好奇的(承认憎恶)我把到位如下:

(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)))) 
+0

叉,添加你需要的功能,并提交拉请求; ^) – noahlz

+0

@noahz我已经提交了一个包含代码的票。无论上游是否认为此功能_desirable_是一个非常值得怀疑的事情 - 但我不确定如果我是他们,我会接受它。 –

+0

我做了这个评论tounge-cheek(出于你提到的原因),但另一方面,API应该是“开放的扩展,关闭修改”。 – noahlz

回答

1

经过一番思考我看到两个基本approches(其中一个我从你):

动态绑定(如你现在这样做):

有人抱怨说动态绑定对大多数提供者的主体有效; “只有当从那里打电话时,这种方式表现如何?”。虽然我个人并不认为这是一件坏事(有些人)会这样做。在这种情况下,它完全符合你的愿望,只要你有一个决定你是否想要关键字化的字符串,这应该工作。如果你添加第二个改变他们的点,并且有一个代码路径跨越两个地方......你自己做的。但是,嘿,工作代码有它的优点。

继承:

good'ol Java的方式或使用Clojure的附加特殊heirarchies你可以扩展你身边掠过被keywordized串-widgewhatzit扩展widgewhatzit和添加一个新的处理程序对象的类型您的具体子类。这只适用于某些情况,并在设计的其余部分强制使用不同的对象风格。一些聪明人也会争辩说,它仍然遵循最令人惊讶的原则,因为当通过另一条代码路径调用时,对象的类型将会有所不同。


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

+0

我不能做基于子类的协议实现方法,因为正在处理的对象是由库本身生成的(实际上是由库_it_使用)。这将远远超出我的偏好,因为它完全取决于其他用户。 –

+0

...顺便说一下,我不喜欢当前方法的主要原因是它修改了库代码。是的,新行为应该被动态绑定切换...但是如果上行调整了原始代码路径,并且我没有将该功能应用于我的重写版本,则给定Clojure环境中的库的_all_用户将失去上游改变,不仅仅是我自己的代码。我已经在Ruby和Python世界中用猴子补丁烧了足够多,因此非常非常谨慎地在此认可它。 –

+0

好吧,现在你发布了它,有人会按照你的例子;-)你正在进入另一个图书馆,并摆弄它的位,所以可能会有一些限制,如何得到干净: -/ –