基于 "isa?" 的多方法如何比 instanceof 的语法糖更重要?

How is an "isa?" based multimethod more than syntax sugar for instanceof?

我正在以 clojure site 中的示例为例。

(defmulti foo class)
(defmethod foo ::collection [c] :a-collection)
(defmethod foo String [s] :a-string)

(foo [])
:a-collection

(foo (java.util.HashMap.))
:a-collection

(foo "bar")
:a-string

这个功能很酷。我试图理解为什么这优于(例如)java 中基于 instanceof 的实现的技术原因。在我看来,它在功能上基本等同,语法更好。

public <T> String foo(final T t) {
    if (t instanceof Collection) {
        return "a-collection";
    } else if (t instanceof String) {
        return "a-string";
    } else {
        throw new IllegalArgumentException("Undefined - no available dispatch");
    }
}

为什么 multimethods 被认为是基于访问者模式的双重分派的一个很好的替代品,而 instanceof 却不是,因为它们看起来本质上是在做同样的事情?

评论中讨论的好处之一是 defmultidefmethod 可以由不同的用户在不同的文件中完成。一个很好的例子是 Clojure 自己的 print-method 多方法。

From the docs,我们看看如何为我们创建的新记录类型定义自定义 print-method

(deftype XYZ [])

; without custom print-method defined:
user=> (prn (XYZ.))
#<XYZ user.XYZ@2670d85b> 

; Note, this hooks into the pre-existing `(defmulti print-method ...)`
(defmethod print-method XYZ [v ^java.io.Writer w] 
  (.write w "<<-XYZ->>"))

; with print-method
user=> (prn (XYZ.))
<<-XYZ->>

因此,虽然它与巨大的 cond 语句有相似之处,但它更灵活、更简洁。