ランタイムポリモーフィズム
ランタイムポリモーフィズムを利用するシステムは、変更や拡張が容易です。Clojureは、いくつかの方法でポリモーフィズムをサポートしています。
-
Clojureランタイムのほとんどのコアインフラストラクチャデータ構造は、Javaインターフェースによって定義されています。
-
Clojureは、proxy(JVMホストを参照)を使用して、ClojureでJavaインターフェースの実装を生成することをサポートしています。
-
Clojure言語は、マルチメソッドを使用して、クラス階層とカスタム階層の両方に沿ってポリモーフィズムをサポートしています。
-
Clojure言語はまた、プロトコル(ただし、JVMの既存の呼び出し機能を利用するために、クラスポリモーフィズムに限定)を使用した高速なポリモーフィズム形式もサポートしています。
Clojureのマルチメソッドは、OO、型、および継承の制約から解放された、シンプルでありながら強力なランタイムポリモーフィズムのメカニズムです。ランタイムポリモーフィズムの基本的な考え方は、単一の関数指定子が、呼び出しの値に基づいて、独立して定義された複数の関数定義にディスパッチすることです。従来のシングルディスパッチOO言語の場合、その値は「レシーバー」または「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
マルチメソッドは、あらゆる点で関数(fn)です。たとえば、mapなどに渡すことができます。
インターフェースと同様に、Clojureプロトコルは関数仕様(実装なし)のみを定義し、型が複数のプロトコルを実装できるようにします。さらに、プロトコルは新しい型に対する後からの動的な拡張に開かれています。プロトコルは、ポリモーフィックメソッド呼び出しのネイティブJavaパフォーマンスを利用するために、クラス型へのディスパッチのみに限定されています。詳細については、プロトコルのページを参照してください。