2017-03-06 44 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 { ... } 

如果我知道(並且是穩定信心)的基礎對象,我可以寫一個多方法派遣由該方法返回的各種對象:

(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

韋爾普,現在我覺得自己像個白癡。感謝您描述'isa?'部分。那是我錯過的方面。 – user12341234

0

您可以使用多方法的調度功能,以每個接口映射到「調度值」,然後使用這些值調度指揮的事情正確的代碼。這個調度函數在接口之間的隱式層次結構中定義,所以你總是最終得到代碼需要去的一個地方。

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以任意方式來構建這些。