Privilégier la composition à l'héritage
est une phrase très populaire. J'ai lu plusieurs articles et chaque article dit à la fin
utilisez l'héritage lorsqu'il existe une relation IS-A pure entre les classes.
Un exemple de cet article :
Ici, entre Apple et Fruit, la relation IS-A est claire, c’est-à-dire Apple IS-A Fruit, mais l’auteur l’a également montrée sous le nom Apple HAS-A Fruit (composition) pour montrer le piège lorsqu’elle est implémentée avec héritage.
Je suis devenu un peu confus ici que ce qui est le sens de la déclaration
utilisez l'héritage lorsqu'il existe une relation IS-A pure entre les classes.
L'utilisation de la composition sur l'héritage signifie-t-elle toujours essayer d'appliquer la composition même si il existe une relation IS-A pure et ne laisser l'héritage que dans les cas où la composition n'a pas de sens?
Lorsque vous utilisez l'héritage pour réutiliser le code de la super-classe, plutôt que pour redéfinir les méthodes et définir un autre comportement polymorphe, cela indique souvent que vous devez utiliser la composition plutôt que l'héritage.
La classe Java.util.Properties
est un bon exemple de mauvaise utilisation de l'héritage. Plutôt que en utilisant une table de hachage pour stocker ses propriétés, elle étend Hashtable, afin de réutiliser ses méthodes et d’éviter de réimplémenter certaines d’entre elles en utilisant la délégation.
Je pense que c'est l'un des points les plus discutés de la conception orientée objet. Comme suggéré dans l'article, la composition est toujours préférable à l'héritage. Cela ne signifie pas que vous ne devriez jamais utiliser l'héritage. Vous devriez savoir où cela a plus de sens (ce qui peut être discuté).
Il y a de nombreux avantages à utiliser la composition, parmi lesquels:
Dans l'article, il n'y a pas une telle phrase:
use inheritance when there is pure IS-A relationship between classes
De plus, Google ne l'a pas trouvé ailleurs que dans votre message.
À la place, l'article se lit comme suit:
Make sure inheritance models the is-a relationship.
My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.
Cela signifie que s'il existe une relation IS_A, essayez d'utiliser d'abord l'héritage, et non la composition. Et il n'y a pas de préférence de using composition over inheritance
- chacun est bon pour son propre rôle.
Je suppose qu'une bonne ligne directrice serait:
Lorsqu'il existe une relation IS-A, utilisez l'héritage. Sinon, utilisez composition.
La raison en est liée à un autre concept de la conception orientée objet, le polymorphisme. Le polymorphisme est une caractéristique de nombreux langages OOP dans lesquels un objet peut être utilisé à la place d'un autre objet, à condition que la classe du premier soit une sous-classe du second.
Pour illustrer, imaginez si vous avez une fonction qui prend un type d'animal. Lorsque vous utilisez l'héritage, vous n'avez qu'une seule fonction:
void feed( Animal a );
Le polymorphisme nous assure que toute sous-classe d’animal que nous mettons en sera acceptée. Sinon, nous serons obligés d'écrire une fonction pour chaque type. Je pense que les avantages de ceci dépassent ses inconvénients (ex. Encapsulation réduite).
S'il n'y a pas de relation IS-A, je pense que le polymorphisme ne sera pas très efficace. Il serait donc préférable d’utiliser la composition et d’avoir une meilleure encapsulation/isolation entre les classes.
De plus, j'aimerais ajouter que Motif de décorateur est un exemple où vous pouvez utiliser la composition plutôt que l'héritage et ajouter des responsabilités aux objets de manière dynamique. L'exemple de modèle Decorator est mentionné dans Effective Java dans la rubrique "Favoriser la composition par rapport à l'héritage". Pour prendre un exemple de l'API Java; BufferedReader décore un Reader (au lieu d'étendre FileReader, PipedReader, FilterReader, etc.) et a donc la possibilité de décorer tout type de Reader. La fonctionnalité de mise en mémoire tampon est associée à ces lecteurs lors de l'exécution, qui correspond au modèle Decorator.
Ici, une extension par sous-classe ne serait pas pratique.
Utilisez l'héritage lorsque la relation est permanente. N'utilisez pas l'extension uniquement pour avoir un comportement libre. C’est ce à quoi ils font référence dans l’exemple IS-A. Étendre uniquement si la classe d'extension est vraiment une extension du parent. Il y aura des moments où ce n'est pas coupé et sec, mais en général. La composition offre également une flexibilité future si vous devez vous éloigner de la "bonne" classe.
Ceci est un ancien mais excellent article sur étend:
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
Je dirais non. Dans le scénario fruit/pomme, il est judicieux d'utiliser l'héritage. L'auteur de l'article confirme également que: "Dans l'exemple ci-dessus, une pomme est probablement un fruit, alors je serais enclin à utiliser l'héritage".
Si votre sous-classe est clairement une super-classe, l'héritage convient. En pratique cependant, vous trouverez beaucoup plus de situations qui sont mieux résolues par la composition.