2017-07-04 5 views
1

Quelle est certainement la meilleure façon d'appeler une méthode différente d'une classe en fonction d'un type d'objet différent dans une liste?Meilleure façon d'acheminer la méthode appelant à partir de la liste en Java

exemple courant:

public class Dog extends Animals{ 
    ... 
    public void say(){ 
    System.out("i'm a dog"); 
} 

public class Cat extends Animals{ 
    ... 
    public void say(){ 
    System.out("i'm a cat"); 
} 

public class OtherClass { 
    public void route(){ 
    List<Animals> aList = new ArrayList<>(); 
    a.add(new Dog()); 
    a.add(new Cat()); 
    for(Animals a:aList) 
    methodOverloaded(a); ---> that's the point <--- 
    } 
    public methodOverloaded(Dog d){ 
    d.say(); 
    } 

    public methodOverloaded(Cat c){ 
    c.say(); 
} 
} 

Bien sûr, l'objectif est métaphorique impression I'm a dog sur la première itération et I'm a cat sur le deuxième fonctionnement methodOverloaded().

J'ai essayé

  • Visiteur Motif
  • instanceOf()

mais je suis à la recherche d'une meilleure solution.

edit: Je veux appeler stricieusement les méthodes surchargées de l'exemple OtherClass.

+0

Veuillez lire ma réponse mise à jour, peut-être que ce sera plus clair maintenant. –

+0

merci beaucoup – tommasoballardini

Répondre

2

Le meilleur moyen est de définir la méthode abstraite dans Animal et de la surcharger dans les classes enfants. C'est comme ça que le polymorphisme fonctionne.

Pas besoin de surcharges.

public abstract class Animal { 
    public abstract void say(); 
} 

public class Dog extends Animal { 

    @Override 
    public void say() { 
     System.out.println("Bark"); 
    } 
} 

public class Cat extends Animal { 

    @Override 
    public void say() { 
     System.out.println("Meow"); 
    } 
} 

Utilisation:

public class Main() { 
    public static void main(String[] args) { 
     List<Animals> aList = new ArrayList<>(); 
     a.add(new Dog()); 
     a.add(new Cat()); 
     for (Animals a : aList) 
      a.say(); 
    } 
} 

Sortie:

Bark 
Meow 

____UPDATE_1

Je voudrais ajouter som e commentaires pourquoi la surcharge de ces méthodes n'est pas une bonne idée.

Si vous ajoutez ce qui suit à votre code - il compilera:

public methodOverloaded(Animal a) { 
    a.say(); 
} 

Mais cela ne fonctionnera pas comme vous vous attendez. Il appellera public methodOverloaded(Animal a) pour tous les éléments de List.

Pourquoi cela se produit-il?

Pour toutes les itérations de la boucle, le type de compilation du paramètre est Animal. Le type d'exécution est différent à chaque itération, mais cela n'affecte pas le choix de la surcharge. Comme le type de compilation du paramètre est Animal, la seule surcharge applicable est la troisième.

Le comportement de ce programme est contre-intuitif car la sélection parmi les méthodes surchargées est statique, tandis que la sélection parmi les méthodes surchargées est dynamique.

La version correcte d'une méthode substituée est choisie au moment de l'exécution, en fonction du type d'exécution de l'objet sur lequel la méthode est invoquée.

Cela peut être corrigé avec:

public methodOverloaded(Animal a) { 
    if (a instanceof Cat) ? "Meow" : 
     (a instanceof Dog) ? "Bark" : "Unknown Animal" 
} 

Bien sûr suggéré l'option avec des méthodes prépondérants démontre une meilleure approche et un code plus propre.

De plus, une politique prudente et prudente consiste à ne jamais exporter deux surcharges avec le même nombre de paramètres, car cela peut perturber le client de l'API. Vous pouvez toujours donner des noms différents aux méthodes au lieu de les surcharger.

Mais il y a le cas où au moins un paramètre formel correspondant dans chaque paire de surcharges a un type "radicalement différent" (quand il est clairement impossible de lancer une instance de l'un ou l'autre type) dans les deux surcharges. Par exemple, ArrayList a un constructeur qui prend un int et un second constructeur qui prend un Collection. Il est difficile d'imaginer une confusion sur lequel de ces deux constructeurs sera invoqué dans n'importe quelles circonstances.

+0

ok mais si je veux stricte appeler les méthodes surchargées de l'exemple ** OtherClass **? – tommasoballardini

+1

Vous pouvez le faire, mais ce n'est pas un bon moyen de concevoir vos classes. Vos deux méthodes peuvent être combinées en une, car elles ont une logique partagée sur la même abstention. Le principe d'inversion de dépendance encourage le travail avec des abstractions. Si vous avez d'autres objectifs, veuillez le décrire, je vais essayer de vous aider. Dans votre exemple, cela n'a aucun sens de surcharger ces deux méthodes. –

+0

Les meilleures pratiques pour votre exigence est d'utiliser le modèle de conception d'usine dans Java. –

0

Vous devez définir la méthode chez l'animal et le rendre abstrait

abstract class Animal { 
    public abstract void say(); 
} 

cette façon, vous pouvez remplacer cette méthode dans chaque enfant d'animaux, et tout ce que vous avez à faire est a.say() chaque objet appellera leur méthode respective.

0

Vous pouvez le faire comme ceci:

for(Animals a:aList){ 
    if(a instanceof Dog){ 
     methodOverloaded((Dog) a); 
    }else if(a instanceof Cat){ 
     methodOverloaded((Cat) a); 
    } 
} 

Mais selon le scénario que vous avez décrit dans la question, @ réponse J-Alex est un bon moyen d'aller.

0

Je peux vous montrer comment le "motif de conception d'usine" est approprié ici. vous classe principale Définir comme:

public abstract class Animal { 
    public abstract void say(); 
} 


public class Dog extends Animal { 

    @Override 
    public void say() { 
     System.out.println("Bark"); 
    } 
} 
public class Cat extends Animal { 

    @Override 
    public void say() { 
     System.out.println("Meow"); 
    } 
} 

public class FactoryClass{ 

public static Animal getCorrectAnimal(String type){ 
if("Cat".equalsIgnoreCase(type)) return new Cat(); 
else if ("Dog".equalsIgnoreCase(type)) return new Dog(); 

return null; 
} 

} 


public class TestFactoryClass { 

    public static void main(String[] args) { 
     Animal an = ComputerFactory.getCorrectAnimal("Cat"); 
     List<Animals> aList = new ArrayList<>(); 
     a.add(FactoryClass.getCorrectAnimal("Dog")); 
     a.add(FactoryClass.getCorrectAnimal("Cat")); 
     for (Animals a : aList) 
      a.say(); 
    } 

    } 

} 

Croyez-moi, si vous analysez le niveau d'abstraction ici, il est génial. Le client/consommateur n'a jamais à connaître la classe Chien ou Chat, il/elle doit juste connaître le type et une classe abstraite générale Animal. Vous pouvez même vous en débarrasser si vous utilisez un niveau d'abstraction supérieur; vous pouvez lire "Abstract Factory Design" pour cela. De cette façon, vous exposez le moins de vos fonctionnalités de classe (comme ici vous avez exposé Dog et Cat en les utilisant directement avec new dans la classe principale). S'il vous plaît upvote si vous êtes satisfait.

+0

@tommasoballardini Aussi aucun casting ou utilisation directe de classe n'est nécessaire ici. –

+0

'Factory' est un motif de conception créative, le mécanisme de 'routage' ici est toujours polymorphisme. Vous avez fait la même chose mais avec une autre approche de création d'objet.Et une 'Factory' n'a pas de sens si vous avez un constructeur public. Ne pas gâcher les responsabilités des différents composants de l'application. –

+0

@ J-Alex c'est pourquoi c'est l'un des meilleurs moyens. S'il vous plaît essayez de comprendre la question posée par tommasoballardini. Ne trouvez-vous pas que c'est la meilleure approche? –