Java接口上的Clojure多方法调度

Java接口上的Clojure多方法调度,clojure,multimethod,Clojure,Multimethod,假设我有一个Java方法,它返回某个父接口的对象。此函数返回的对象类没有文档记录,但是有丰富且文档记录良好的接口层次结构,所有这些接口都扩展了父接口。例如: public class Person { public IMeal favoriteMeal() { ... } } public interface IBreakfast extends IMeal { ... } public interface ILunch extends IMeal { ... } public inte

假设我有一个Java方法,它返回某个父接口的对象。此函数返回的对象类没有文档记录,但是有丰富且文档记录良好的接口层次结构,所有这些接口都扩展了父接口。例如:

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] ...)

您可以使用multimethods的dispatch函数将每个接口映射到一个dispatch值,然后使用这些dispatch值将内容定向到正确的代码。此分派函数在接口之间的隐式层次结构中定义,因此您总是以代码需要到达的确切位置结束

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

如果在dispatch函数中定义层次结构变得烦人,您可以切换到使用以任意方式构建这些层次结构

这已经非常有效了:

注:

然后:

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

注意,多重方法总是使用isa?在可能的自定义层次结构上内部。伊莎呢?关键词Callable是真的。

Welp,现在我觉得自己像个白痴。感谢您描述isa?部分这就是我所缺少的方面。
(defmulti print-stuff class)
(defmethod print-stuff Callable [x] {:callable x})
(defmethod print-stuff :default [x] :not-found)
(print-stuff :foo) ;; => :callable