2017-03-06 2 views
2

私はいくつかの親インターフェイスのオブジェクトを返すJavaメソッドがあります。この関数が返すオブジェクトのクラスは文書化されていませんが、親インタフェースを拡張している豊富で十分に文書化されたインタフェースの階層があります。だから、例えば:私は知っていた(との安定性に自信があった)基礎となるオブジェクト場合JavaインターフェイスでClojure Multimethodディスパッチ

public class Person { 
    public IMeal favoriteMeal() { ... } 
} 

public interface IBreakfast extends IMeal { ... } 
public interface ILunch extends IMeal { ... } 
public interface IBrunch extends IBreakfast, ILunch { ... } 

、私はそのメソッドによって返されたさまざまなオブジェクトにディスパッチするmultimethodを書くことができ:

(defmulti place-setting class) 
(defmethod place-setting Omelet [meal] ...) 

しかし、インターフェイスだけが公開されているので、私はむしろそれらをディスパッチしたいと思います。インターフェイスにディスパッチする(良い)方法はありますか?おそらくのように:

(defmulti place-setting magic-interface-dispatch-fn) 
(defmethod place-setting IBreakfast [meal] ...) 

答えて

4

これは、すでに完全に正常に動作します:

注:その後、

public interface IFn extends Callable, Runnable 
public class Keyword implements IFn 

そして:

(defmulti print-stuff class) 
(defmethod print-stuff Callable [x] {:callable x}) 
(defmethod print-stuff :default [x] :not-found) 
(print-stuff :foo) ;; => :callable 

注意、マルチメソッドは常に内部的に(潜在的にカスタム)階層上のisa?を使用しています。 (isa? Keyword Callable)が真です。

+0

Welp、今私は馬鹿のように感じる。 'isa? 'の部分を説明してくれてありがとう。それが私が見逃していた面でした。 – user12341234

0

あなたは「派遣値」に、各インターフェイスをマッピングして、正しいコードに物事を指示するために、これらのディスパッチ値を使用するマルチメソッドのディスパッチ機能を使用することができます。このディスパッチ関数は、インターフェイス間の暗黙的な階層を定義するので、常にコードが必要とする1つの場所で終わります。

hello.core> (defmulti foo (fn [meal] (condp instance? meal 
             java.util.Collection ::breakfast 
             java.lang.Double ::lunch))) 
nil 
hello.core> (defmethod foo ::breakfast 
       [meal] 
       (count meal)) 
#multifn[foo 0x2b6e7712] 
hello.core> (defmethod foo ::lunch 
       [meal] 
       meal) 
#multifn[foo 0x2b6e7712] 
hello.core> (foo 2.3) 
2.3 
hello.core> (foo [1 2 3]) 
3 

ディスパッチ機能に階層を定義すると、迷惑を取得した場合は、任意の方法でこれらを構築するためにclojure's built in hierarchy featureの使用に切り替えることができます。

関連する問題