2017-03-06 1 views
2

Dites que j'ai une méthode Java qui renvoie un objet de l'interface parent. Les classes des objets retournés par cette fonction sont non documentées, mais il existe une hiérarchie riche et bien documentée d'interfaces qui étendent l'interface parent. Ainsi, par exemple:Répartition de Clojure Multimethod sur l'interface Java

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

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

Si je savais (et était confiant dans la stabilité) les objets sous-jacents, je pourrais écrire un multiméthode à être envoyé sur les différents objets retournés par cette méthode:

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

Cependant, comme seules les interfaces sont publiques, je préfère les envoyer. Existe-t-il un (bon) moyen de distribuer sur les interfaces? Peut-être comme:

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

Répondre

4

Cela fonctionne déjà parfaitement bien:

Note:

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

Et puis:

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

Remarque, Multiméthodes utilise toujours isa? en interne sur la hiérarchie (potentiellement personnalisée). Et (isa? Keyword Callable) est vrai.

+0

Welp, maintenant je me sens comme un idiot. Merci d'avoir décrit la partie 'isa? C'était l'aspect qui me manquait. – user12341234

0

Vous pouvez utiliser la fonction d'envoi de Multiméthodes à la carte chaque interface à une « valeur d'expédition » et ensuite utiliser ces valeurs d'expédition pour diriger les choses au bon code. Cette fonction de répartition définit implicitement la hiérarchie entre les interfaces afin que vous ayez toujours exactement le même emplacement que le code.

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 

Si la définition de la hiérarchie dans la fonction de répartition devient ennuyeux, vous pouvez passer à l'aide clojure's built in hierarchy feature pour construire ces de manière arbitraire.