web-dev-qa-db-fra.com

Avantage du polymorphisme

Quand j'ai commencé à chercher les avantages du polymorphisme, j'ai trouvé avec this question ici. Mais ici, je n'ai pas pu trouver ma réponse. Permettez-moi de dire ce que je veux trouver. Ici, j'ai quelques cours:

class CoolingMachines{
    public void startMachine(){
        //No implementationion
    }
    public void stopMachine(){
        //No implementationion
    }
}

class Refrigerator extends CoolingMachines{
    public void startMachine(){
        System.out.println("Refrigerator Starts");
    }
    public void stopMachine(){
        System.out.println("Refrigerator Stop");
    }
    public void trip(){
        System.out.println("Refrigerator Trip");
    }
}

class AirConditioner extends CoolingMachines{
    public void startMachine(){
        System.out.println("AC Starts");
    }
    public void stopMachine(){
        System.out.println("AC Stop");
    }
}

public class PolymorphismDemo {
    CoolingMachines cm = new Refrigerator();
    Refrigerator rf = new Refrigerator();
}

Maintenant, ici, j'ai créé deux objets dans la classe Demo et sont des références de Refrigerator. J'ai complètement compris qu'à partir de l'objet rf, je peux appeler la méthode trip() de Refrigerator, mais cette méthode sera masquée pour le cm objet. Maintenant, ma question est pourquoi devrais-je utiliser le polymorphisme ou pourquoi devrais-je utiliser

CoolingMachines cm = new Refrigerator();

quand je vais bien avec

Refrigerator rf = new Refrigerator();

L'efficacité de l'objet polymorphe est-elle bonne ou légère? Quel est le but et la différence de base entre ces deux objets? Y a-t-il une différence entre cm.start(); et rf.start()?

69
khan

C'est utile lorsque vous manipulez des listes ... Un petit exemple:

List<CoolingMachines> coolingMachines = ... // a list of CoolingMachines 
for (CoolingMachine current : coolingMachines) {
    current.start();
}

Ou lorsque vous souhaitez autoriser une méthode à fonctionner avec n'importe quelle sous-classe de CoolingMachines

71
pgras

Dans les cas où vous êtes vraiment d'accord pour connaître la classe concrète, il n'y a aucun avantage. Cependant, dans de nombreux cas, vous voulez pouvoir écrire du code qui ne connaît que la classe ou l'interface de base.

Par exemple, regardez Iterables in Guava - c'est beaucoup de méthodes qui (la plupart du temps) ne se soucient pas de l'implémentation de Iterable est en train d'être utilisé. Souhaitez-vous vraiment tout ce code séparément pour chaque implémentation?

Là où vous pouvez coder vers une classe de base abstraite ou une interface, vous vous autorisez à utiliser ultérieurement d'autres implémentations qui partagent la même API publique, mais peuvent avoir différentes implémentations. Même si vous ne voulez qu'une seule implémentation de production , vous pouvez très bien souhaiter des implémentations alternatives pour les tests. (La mesure dans laquelle cela s'applique dans une large mesure dépend de la classe en question.)

58
Jon Skeet

Parce que plus tard, si vous souhaitez utiliser AirConditioner au lieu de Refrigerator pour le refroidissement, alors seul le code que vous devez modifier est CoolingMachines cm = new AirConditioner();

28
Naveen

La raison pour laquelle vous souhaitez utiliser

CoolingMachines cm = new Refrigerator();

c'est que vous pourrez plus tard facilement utiliser un autre CoolingMachines. Il vous suffit de modifier cette seule ligne de code et le reste du code fonctionnera toujours (car il n'utilisera que les méthodes de CoolingMachines, ce qui est plus général qu'une machine spécifique, comme un Refrigerator).

Ainsi, pour une instance particulière de Refrigerator, les appels cm.start(); et rf.start() fonctionnent de la même manière mais cm peut également être un CoolingMachines objet. Et cet objet pourrait avoir une implémentation différente de start().

17
Simeon Visser

Première réponse:

Utilisez le polymorphisme pour la substitution de méthode et la surcharge de méthode. Autres méthodes de classe utilisées dans une classe différente puis deux options: première méthode héritée, seconde méthode écrasée. Ici, étendez l'interface: utilisez-les, ou méthode d'implémentation: logique, écrivez-les. Polymorphisme utilisé pour la méthode, l'héritage de classe.

Deuxième réponse:

Y a-t-il une différence entre cm.start(); et rf.start();?

Oui, les deux sont des objets complètement différents les uns des autres. Ne créez pas d'objets d'interface car Java ne prend pas en charge les objets d'interface. Premier objet créé pour l'interface et deuxième pour la classe Réfrigérateur. Deuxième objet en ce moment.

7
Solomon Bindavid

La réponse la plus générale à la partie générale de votre question (pourquoi devrais-je utiliser le polymorphisme?) Est que le polymorphisme réalise quelques principes de conception orientés objet critiques, par exemple:

  • réutilisation de code: en mettant tout code commun à toutes vos "machines de refroidissement" dans la machine de refroidissement, vous n'avez besoin d'écrire ce code qu'une seule fois et toutes les modifications apportées à ce code se répercutent instantanément.

  • abstraction: les cerveaux humains ne peuvent garder qu'une trace de tant de choses, mais ils sont bons dans les catégories et les hiérarchies. Cela permet de comprendre ce qui se passe dans un grand programme.

  • encapsulation: chaque classe cache les détails de ce qu'elle fait et s'appuie simplement sur l'interface de la classe de base.

  • séparation des préoccupations: beaucoup de programmation orientée objet consiste à attribuer des responsabilités. Qui va s'en charger? Les préoccupations spécifiques peuvent être classées en sous-classes.

Le polymorphisme n'est donc qu'une partie de la plus grande image oo, et les raisons de son utilisation n'ont parfois de sens que si vous allez essayer de faire une "vraie" programmation oo.

5
Scruffy

Un cas d'utilisation simple du polymorphisme est que vous pouvez avoir un tableau de CoolingMachines où l'élément 0 est un réfrigérateur et l'élément 1 est un climatiseur, etc.

Vous n'avez pas besoin d'effectuer de vérifications ni de vous assurer de l'objet auquel vous avez affaire pour appeler le voyage ou démarrer, etc.

Cela peut être un grand avantage lors de la saisie d'un utilisateur et de l'itération sur tous les objets et d'appeler des fonctions similaires

3
Simon McLoughlin

L'utilisation polymorphe de vos objets permet également de créer des usines ou des familles de classes connexes, ce qui est un élément important de la façon dont Factory Design Pattern est implémenté. Voici un exemple très basique d'usine polymorphe:

public CoolingMachine CreateCoolingMachines(string machineType)
{
    if(machineType == "ref")
        return new Refrigerator();
    //other else ifs to return other types of CoolingMachine family
}

utilisation de l'appel du code ci-dessus:

CoolingMachine cm = CreateCoolingMachine("AC"); //the cm variable will have a reference to Airconditioner class which is returned by CreateCoolingMachines() method polymorphically

Imaginez également que vous disposez d'une méthode comme ci-dessous qui utilise le paramètre de classe concret Refrigerator:

public void UseObject(Refrigerator refObject)
{
    //Implementation to use Refrigerator object only
}

Maintenant, si vous modifiez l'implémentation de la méthode UseObject() ci-dessus pour utiliser la plupart des paramètres de classe de base génériques, le code appelant aurait l'avantage de passer n'importe quel paramètre de manière polymorphe qui peut ensuite être utilisé à l'intérieur de la méthode UseObject() :

public void UseObject(CoolingMachine coolingMachineObject)
{
    //Implementation to use Generic object and all derived objects
}

Le code ci-dessus est désormais plus extensible car d'autres sous-classes pourraient être ajoutées ultérieurement à la famille des CoolingMachines, et les objets de ces nouvelles sous-classes fonctionneraient également avec le code existant.

2
VS1

Je vais donner un exemple facile à comprendre. Disons que vous avez du json

{"a":[1,2],"sz":"text", "v":3, "f":1.2}

Disons maintenant par programmation que vous souhaitez répertorier le nom, le type et la valeur. Au lieu d'avoir un commutateur () pour chaque type (tableau pour a, chaîne pour sz, etc.), vous pouvez simplement avoir un type de base et appeler une fonction qui fait son travail. Il est également plus efficace en termes de processeur que d'utiliser un commutateur avec une douzaine de types.

Ensuite, il y a des plugins, des bibliothèques et du code étranger avec des raisons d'interface.

2
user34537