Reputation: 7193
Say I have a Java method that returns an object of some parent interface. The classes of the objects returned by this function are undocumented, however there is a rich and well documented hierarchy of interfaces all extending the parent interface. So for example:
public class Person {
public IMeal favoriteMeal() { ... }
}
public interface IBreakfast extends IMeal { ... }
public interface ILunch extends IMeal { ... }
public interface IBrunch extends IBreakfast, ILunch { ... }
If I knew (and was confident in the stability of) the underlying objects, I could write a multimethod to dispatch on the various objects returned by that method:
(defmulti place-setting class)
(defmethod place-setting Omelet [meal] ...)
However, since only the interfaces are public, I'd rather dispatch on those. Is there a (good) way to dispatch on interfaces? Perhaps like:
(defmulti place-setting magic-interface-dispatch-fn)
(defmethod place-setting IBreakfast [meal] ...)
Upvotes: 2
Views: 306
Reputation: 4713
This already works perfectly fine:
Note:
public interface IFn extends Callable, Runnable
public class Keyword implements IFn
And then:
(defmulti print-stuff class)
(defmethod print-stuff Callable [x] {:callable x})
(defmethod print-stuff :default [x] :not-found)
(print-stuff :foo) ;; => :callable
Note, multimethods always uses isa?
internally on the (potentially custom) hierarchy. And (isa? Keyword Callable)
is true.
Upvotes: 4
Reputation: 91534
You can use the dispatch function of multimethods to map each interface to a "dispatch value" and then use these dispatch values to direct things to the correct code. This dispatch function defines in implicit hierarchy between the interfaces so you always end up with exactly one place the code needs to go.
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
If defining the hierarchy in the dispatch function gets annoying, you can switch to using clojure's built in hierarchy feature to build these in arbitrary ways.
Upvotes: 0