Clojure多方法与协议

时间:2011-11-09 19:21:31

标签: clojure multimethod

我是Clojure新手并且正在寻找何时使用协议以及何时使用多方法的一些具体示例。我知道协议通常适用于创建类型层次结构和典型的OOP事物,它们是在多方法之后添加到语言中的,并且协议通常具有更好的性能,所以我的问题是:

协议是否意味着取代多方法?如果没有,你能给我一个例子,我会用多方法代替协议吗?

4 个答案:

答案 0 :(得分:35)

协议和多方法是互补的,适用于略有不同的用例。

  • 协议根据第一个参数的类型提供高效的多态分派。因为它能够利用一些非常有效的JVM功能,所以协议可以为您提供最佳性能
  • 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!")))

请注意,由于以下两个原因,您无法在此处使用协议:

  • 调度函数需要使用两个参数来确定要使用的方法实现(即,它是多个调度的情况)。
  • 你也无法区分第一个参数的类型(可能总是一个数值)

答案 1 :(得分:34)

多方法更强大,更昂贵,

在足够的时候使用协议但如果您需要根据从火星上看到的月相来发送,那么多方法是您的最佳选择。

协议的存在是为了让简单的东西保持简单,并为clojure提供一种生成与等效java相同的字节码的方法。似乎大多数人大多数时候都在使用协议。当我需要派遣多个参数时,我使用multimethods,虽然我不得不承认这只出现过一次,而且isa层次结构的使用频率更低(由我来)。所以简而言之在需要时使用Multimethods

最好的例子我的expierence就在一开始就在core.clj

答案 2 :(得分:6)

正如亚瑟所提到的,多方法更强大,更昂贵。实际上,协议可以被认为是多个方法的特殊情况,其中调度函数是class。当然,事实并非如此,因为协议不止于此。

如果你需要派遣第一个参数的类以外的东西,你需要使用多方法或重新设计。调度类型是协议的一个很好的用例。

答案 3 :(得分:1)

当你不需要类层次结构时,我喜欢多方法。例如,如果您有一个媒体数据库并且您的记录类似{:media-type :video, :bytes ...},那么您可以使用多方法

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

这样你就可以避免使用中心cond表达式,这样你就可以获得类的模块化。但是你不必经历所有这些"包装类层次结构"样板文件,对我来说是一个应该留给Java世界的祸根。多方法只是功能,对我来说感觉更加诡异。