Clojure

运行时多态

利用运行时多态的系统更容易修改和扩展。Clojure 通过多种方式支持多态性。

  • Clojure 运行时中大多数核心基础数据结构都是由 Java 接口定义的。

  • Clojure 支持使用 proxy 在 Clojure 中生成 Java 接口的实现(参见 JVM 托管)。

  • Clojure 语言使用 多方法 支持类和自定义层次结构的多态性。

  • Clojure 语言还使用 协议 支持更快的多态性形式(但仅限于类多态性,以利用 JVM 现有的调用功能)。

Clojure 多方法是一种简单而强大的运行时多态机制,它摆脱了面向对象、类型和继承的束缚。运行时多态的基本思想是,一个函数标识符根据调用的某个值分派到多个独立定义的函数定义。对于传统的单分派面向对象语言,该值是“接收者”或“this”的类型。CLOS 通用函数将分派值扩展到多个参数的类型或值的组合,因此它们是多方法。Clojure 多方法更进一步,允许分派值为参数的任意函数的结果。Clojure 不支持实现继承。

多方法使用 defmulti 定义,它接受多方法的名称和分派函数。方法使用 defmethod 独立定义,传递多方法名称、分派和函数体。

(defmulti encounter (fn [x y] [(:Species x) (:Species y)]))
(defmethod encounter [:Bunny :Lion] [b l] :run-away)
(defmethod encounter [:Lion :Bunny] [l b] :eat)
(defmethod encounter [:Lion :Lion] [l1 l2] :fight)
(defmethod encounter [:Bunny :Bunny] [b1 b2] :mate)
(def b1 {:Species :Bunny :other :stuff})
(def b2 {:Species :Bunny :other :stuff})
(def l1 {:Species :Lion :other :stuff})
(def l2 {:Species :Lion :other :stuff})
(encounter b1 b2)
-> :mate
(encounter b1 l1)
-> :run-away
(encounter l1 b1)
-> :eat
(encounter l1 l2)
-> :fight

多方法在各个方面都是 fns,例如可以传递给 map 等。

与接口类似,Clojure 协议仅定义函数规范(没有实现),并允许类型实现多个协议。此外,协议对新类型的后期动态扩展开放。协议仅限于根据类类型分派,以利用本地 Java 多态方法调用的性能。有关更多详细信息,请参见 协议 页面。