Clojure 在不影响其他用户的情况下扩展库提供的协议

Clojure 在不影响其他用户的情况下扩展库提供的协议,clojure,Clojure,我正在使用第三方库(),并希望为该库还提供处理程序的类型扩展协议 就其本身而言,这已经足够简单了——但有没有任何方法可以做到这一点,而不会影响在同一JVM中运行此库的其他用户?类似于动态var绑定的东西(仅在堆栈上的给定点下生效)将是理想的 目前,我正在做一个无条件覆盖,但使用动态变量来启用修改后的行为;然而,这感觉太像猴子修补我的舒适 对于好奇的人来说,我要提出的(公认的厌恶)如下: (in-ns 'clj-msgpack.core) (def ^:dynamic *keywordize-s

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

就其本身而言,这已经足够简单了——但有没有任何方法可以做到这一点,而不会影响在同一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))))

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

动态绑定(正如您现在所做的那样):

一些人抱怨说,动态绑定坚持大多数支持的原则;“什么?只有在从那里调用时才会这样做?”。虽然我个人并不认为这是件坏事(tm),但有些人确实这么认为。在这种情况下,它非常符合您的愿望,只要您有一个点,您可以决定是否需要关键字字符串,这应该是可行的。如果您添加第二个点将其更改回原来的位置,并添加一个代码路径,该路径将穿过两个井。。。你的工作靠你自己。但是,工作代码有它的优点

继承:

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

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

我不能使用基于子类的协议实现方法,因为正在处理的对象是由库本身生成的(事实上,它使用的是一个图书馆)。否则,这将是我的首选,因为它与其他用户完全无关……顺便说一句,我不喜欢当前方法的主要原因是它修改了库代码。是的,新的行为应该通过动态绑定进行切换……但是如果上游调整了原始的代码路径,而我不采用f在我的重写版本中,库在给定Clojure环境中的所有用户都会丢失上游更改,而不仅仅是我自己的代码。我已经被Ruby和Python世界中的猴子补丁烧坏了,所以非常非常谨慎地在这里认可它。好吧,现在你发布了它,有人会效仿你的例子;-)您正在访问另一个库并旋转它的各个部分,因此它的干净程度可能有一些限制:-/我发布了这个问题,希望有一个rhickey想到的聪明、干净的解决方案,而我以前并不知道。Fork,添加您需要的功能,并提交一个pull请求;^)@我已经提交了一张有代码的票。上游是否认为这一特性是可取的是一个非常值得怀疑的事情,但是——如果我是他们,我不确定我是否会接受。我在Tonge Check上发表了这一评论(出于您提到的原因),但另一方面……API应该“开放供扩展,关闭供修改”