Clojure multimethods与协议

我是一名Clojure新手,正在寻找什么时候使用协议以及何时使用多方法的具体示例。 我知道协议通常是为了创build一个types层次结构和典型的面向对象的东西,它们是在多方法之后添加到语言中的,而且这些协议通常具有更好的性能,所以我的问题是:

协议是否意味着要取代multimethods? 如果没有,你能给我一个例子,我会使用multimethods而不是协议?

多方法更强大,更昂贵,

当它们足够的时候使用协议,但是如果你需要根据从火星上看到的月相来调度,multimethods是你的最佳select。

协议的存在允许简单的东西保持简单,并为clojure提供了一个方法来生成非常相同的字节码,相当于java的。 大多数人似乎大多数时间使用协议。 当我需要派发多个参数时,我使用多方法,但是我不得不承认,这只是一次出现,完整的isa层次更less使用(由我来说)。 所以在你需要的时候使用Multimethods

最好的例子在我的发现是正确的,在core.clj

Protocol和multimethods是互补的,用于略有不同的用例。

  • 协议基于第一个参数的types提供高效的多态调度。 由于能够利用一些非常高效的JVM特性,协议可以为您提供最佳的性能
  • 多方法实现了非常灵活的多态性,可以基于方法参数的任何函数进行调度。 多方法较慢,但非常灵活

一般来说,我的build议是使用协议,除非你有一个特定的情况,需要multimethods。

你可能需要multimethods的情况如下:

 (defn balance-available? [amount balance] (> balance amount)) (defmulti withdraw balance-available?) (defmethod withdraw true [amount balance] (- balance amount)) (defmethod withdraw false [amount balance] (throw (Error. "Insufficient balance available!"))) 

请注意,由于以下两个原因,您不能在这里使用协议:

  • 调度函数需要使用这两个参数来确定使用哪个方法实现(即它是一个多派遣案例)。
  • 你也不能区分第一个参数的types(这大概总是一个数值)

正如亚瑟所说,多方法更强大,更昂贵。 事实上,协议可以被认为是调度函数是class的多方法的特例。 当然,事实并非如此,因为协议不止于此。

如果您需要派发第一个参数类以外的东西,则需要使用多方法或重新devise。 在types上调度是协议的一个很好的用例。

当你不需要类层次结构时,我喜欢multimethods。 例如,如果你有一个媒体数据库,你的logging是{:media-type :video, :bytes ...}那么你可以有一个multimethod

 (defmulti make-grayscale :media-type) 

那么你可以做各种

 ; in video.clj (defmethod make-grayscale :video [record] (ffmpeg ... (:bytes record)) ; in photo.clj (defmethod make-grayscale :photo [record] (imagemagick ... (:bytes record)) 

这样,你可以避免有一个中央condexpression式,所以你得到类的模块化。 但是你不必经历所有的“包装类层次结构”样板文件,这对我来说是一个应该留给Java世界的祸害。 多方法只是function,我觉得更clojuresque。