2008-12-26 15 views
4

j'ai un arbre d'objet qui ressemble àpassant superclasse en tant que paramètre à la méthode attendant sous classe

  Ball 
     / \ 
    LegalBall IllegalBall 

Et j'ai 2 méthodes:

class o { 
AddBall(LegalBall l) 
AddBall(IllegalBall i) 
} 

dans une autre classe que je voudrais faire ce qui suit:

o.AddBall(myBall); 

où myBall est de type Ball. Et l'obtenir pour appeler la méthode correcte en fonction du sous-type. Apparemment, je ne peux pas faire cela ... les arguments ne sont pas applicables.

Est-ce que quelqu'un sait comment je peux réaliser ce que je veux? Ou s'il y a un bon travail autour

Merci

EDIT: l'application que je suis en train de construire est une chose de type tableau de bord de cricket. Donc, selon le type de balle qui est joué, divers autres éléments devraient changer. Mon intention originale était de pouvoir spécifier le type de balle et les points marqués à partir d'une forme d'interface utilisateur, puis de créer une balle de type approprié à partir d'une BallFactory, puis par exemple lorsque j'envoie une balle non à l'équipe ajoutez la valeur sur le score d'équipe mais ajoutez également la valeur au compteur no balls. Mais quand je donne la même balle à l'analyse de Batsmens à traiter il devrait seulement marquer la valeur-1 au total de batteurs.

J'espère que ce n'est pas trop mal une explication de mon intention originale.

Répondre

6

Vous pouvez utiliser le Visitor pattern.

class Basket { 
    void AddBall(LegalBall l) { 
     System.out.println("LegalBall added to basket"); 
    } 

    void AddBall(IllegalBall i) { 
     System.out.println("IllegalBall added to basket"); 
    } 
} 

interface Ball { 
    void AddBall(Basket b); 
} 

class LegalBall implements Ball { 
    void AddBall(Basket b) { 
     b.AddBall(this); 
    } 
} 

class IllegalBall implements Ball { 
    void AddBall(Basket b) { 
     b.AddBall(this); 
    } 
} 

ou pour le rendre plus général:

interface BallVisitor { 
    void visit(LegalBall l); 
    void visit(IllegalBall i); 
} 

interface Ball { 
    void accept(BallVisitor v); 
} 

class LegalBall implements Ball { 
    void accept(BallVisitor v) { 
     v.visit(this); 
    } 
} 

class IllegalBall implements Ball { 
    void accept(BallVisitor v) { 
     v.visit(this); 
    } 
} 

class Basket implements BallVisitor { 
    void visit(LegalBall l) { 
     System.out.println("LegalBall added to basket"); 
    } 

    void visit(IllegalBall i) { 
     System.out.println("IllegalBall added to basket"); 
    } 
} 
+0

Je vais devoir ajouter AddBall à plus que Basket, un certain nombre d'autres objets. Aurai-je besoin d'implémenter une méthode pour chaque type auquel je veux ajouter une balle? – Rocco

+0

Mis à jour avec le cas général. – dalle

+0

Il serait curieux d'ajouter des méthodes "visit" et "accept" à une interface par ailleurs normale. –

-1

Comment voulez-vous qu'il sache lequel appeler? Qu'est-ce qui distingue les deux méthodes que vous vous attendez à ce qu'il appelle l'un et pas l'autre?

3

Vous devriez essayer de mettre en œuvre une méthode que :

class o { 
AddBall(Ball b) 
} 

et essayer de compter sur le polymorphisme pour un comportement différent par rapport à différentes classes. Bien sûr, les détails dépendent de l'implémentation de la hiérarchie Ball.

0

Vous pouvez (ou ne pouvez pas) vouloir (partie de) le modèle de visiteur.

Ajouter une méthode pour Ball:

public abstract void addTo(o o); 

Implementat dans LegalBall et IllegalBall comme

public void addTo(o o) { 
    o.add(this); 
} 
0

Eh bien, il y a le modèle des visiteurs, comme mentionné ci-dessus. Si vous ne pouvez pas ou ne voulez pas modifier Ball, LegalBall ou IllegalBall, vous pouvez essayer d'avoir une seule branche de méthode basée sur le type de balle. Notez que si vous ajoutez plus tard un QuasiLegalBall, ce code se cassera.Le cas général que vous mentionnez est difficile car l'existence de LegalBall et d'IllegalBall n'empêche pas qu'il existe des Balls qui ne rentrent pas dans les deux types que vous avez décrits (du moins du point de vue de la langue).

class o { 
    public void AddBall(Ball b) 
    { 
     if (b instanceof LegalBall) {AddLegalBall(b); } 
     else if (b instanceof IllegalBall) {AddIllegalBall(b); } 
     else { /*error, new type of ball created*/ } 
    } 
    private void AddLegalBall(LegalBall b) { } 
    private void AddIllegalBall(IllegalBall b) { } 
    } 
} 
-1

Je suis d'accord avec l'utilisation des visiteurs.

De plus, si vous n'avez pas accès à la hiérarchie Ball (accès au code source) ou simple, vous n'avez pas envie de modifier quoi que ce soit; vous pouvez modifier votre classe de clients et décider à partir de là. La mauvaise chose bien sûr est que vous finirez avec de nombreuses instructions if/elseif.

Vous aurez besoin d'ajouter la méthode générique (add (Ball)) et de là appelez les autres. C'est rapide, facile et sale.

:)

public class Test { 
    public static void main(String [] args) { 
     Ball ball = new IllegalBall(); 
     Test test = new Test(); 
     test.add(ball); 
     test.add(new IllegalBall()); 
     test.add(new LegalBall()); 
    } 
    private void add(Ball ball){ 
     System.out.println("Generic method: I'll have someone handling this : " + ball); 
     if(ball instanceof IllegalBall) { 
      add((IllegalBall) ball); 
     } else if(ball instanceof LegalBall) { 
      add((LegalBall) ball); 
     } 
    } 
    private void add(IllegalBall ball){ 
     System.out.println("illega-ball: I won't do anything about it! " + ball); 
    } 
    private void add(LegalBall ball) { 
     System.out.println("legal-ball: Hey this is legal I'll do my best!! " + ball); 
    } 
} 

class Ball {} 
class IllegalBall extends Ball {} 
class LegalBall extends Ball {} 

BTW si vous ne possédez pas la référence directement le compilateur l'envoyer à la bonne méthode que dans les 2 derniers appels.

Comme vous pouvez le voir il suffit d'ajouter le code suivant:

private void add(Ball ball){ 
    System.out.println("Generic method: I'll have someone handling this : " + ball); 
    if(ball instanceof IllegalBall) { 
     add((IllegalBall) ball); 
    } else if(ball instanceof LegalBall) { 
     add((LegalBall) ball); 
    } 
} 
+0

Horrible. Ceci est un exemple de manuel sur la façon dont "instanceof" et la surcharge de méthode sont des odeurs de code pour un mauvais design. Vous abusez du système de types. – eljenso

-1

Le modèle des visiteurs et des solutions similaires en utilisant callbacks, dans ce cas semble que d'essayer de plier votre code de manière à obtenir le compilateur pour accepter votre hiérarchie de classe défectueuse.

Je garderais le type Balle, et ferais légalement/illégale une propriété de ce type. Vous auriez seulement o.add (Ball), dans lequel vous vérifiez légalement/illégal basé sur certaines propriétés ou par le biais d'une méthode, isLegal() par exemple. Si l'approche ci-dessus ne semble pas raisonnable, il n'est pas raisonnable d'avoir une seule méthode pour ajouter deux types (très) distincts, et la relation de sous-typage que vous avez proposée ne serait pas la bonne.

0

Utilisez le modèle de visiteur. Le faire sans est lourd, et a fait l'objet de cette question: Work around Java's static method dispatching without Double Dispatch/Visitor patterns.

Cependant, pouvez-vous indiquer votre problème d'origine? Je veux dire, pourquoi avez-vous besoin de ces deux surcharges pour la méthode Add? Peut-être que vous pouvez le résoudre d'une manière complètement différente qui n'a pas besoin de dépendre de l'envoi dynamique comme le modèle de visiteur?