扩展库提供的协议,而不会影响其他用户

Cha*_*ffy 5 clojure

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

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

目前,我正在进行无条件覆盖,但使用动态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))))
Run Code Online (Sandbox Code Playgroud)

Art*_*ldt 1

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

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

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

遗产:

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


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