首页 > 解决方案 > “ISA”是怎样的?基于多方法而不是 instanceof 的语法糖?

问题描述

我从clojure 网站举个例子。

(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 在它们看起来基本上在做同样的事情时却不是?

标签: clojureinstanceofdouble-dispatchmultimethod

解决方案


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

从 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,但它更灵活、更简洁。


推荐阅读