web-dev-qa-db-fra.com

Composition sur l'héritage mais

J'essaie de m'apprendre à m'enseigner des logiciels de l'ingénierie et de faire face à des informations contraignantes qui me confondent.

J'ai appris OOP et quelles classes/interfaces abstraites sont et comment les utiliser, mais je lis, alors je lis celui-ci devrait "favoriser la composition sur l'héritage". Je comprends la composition est quand une La classe compose/crée un objet d'une autre classe à utiliser/interagir avec cette nouvelle fonctionnalité de l'objet.

Donc, ma question est ... suis-je censé utiliser des classes et des interfaces abstraites? Pour ne pas créer de classe abstraite et étendre/hériter de la fonctionnalité de la classe abstraite dans les classes de béton, et composez-vous simplement de nouveaux objets pour utiliser les fonctionnalités de l'autre classe?

Ou, suis-je censé utiliser la composition et hériter de classes abstraites; en utilisant les deux en conjonction? Si oui, pourriez-vous fournir quelques exemples de la manière dont cela fonctionnerait et ses avantages?

Comme je suis le plus à l'aise avec PHP, je l'utilise pour améliorer mon OOP/SE Compétences avant de passer à d'autres langues et transférer mes compétences SE nouvellement acquises, alors des exemples à l'aide de =PHP serait le plus apprécié.

13
MikeMason

La composition sur l'héritage signifie que lorsque vous souhaitez réutiliser ou étendre la fonctionnalité d'une classe existante, il est souvent plus approprié de créer une autre classe qui "enveloppera" la classe existante et utilisera sa mise en œuvre en interne. modèle de décorateur en est un exemple de ceci.

L'héritage n'est pas un bon moyen par défaut de faire face aux scénarios de réutilisation, car vous souhaitez souvent utiliser une partie d'une funtionalalité de classe de base et la sous-classe ne peut pas supporter tout le contrat de la classe de base de manière à satisfaire - principe de substitution de Liskov .

Modèle de modèle est un bon exemple d'un cas où l'héritage est approprié.

Voir Cette réponse pour les directives sur la manière de choisir entre la composition et l'héritage.

19
astreltsov

La composition est quand une classe offre certaines fonctionnalités en instanciant une classe (éventuellement interne) qui implémente déjà cette fonctionnalité, au lieu d'hériter de cette classe.

Donc, par exemple, si vous avez une classe qui modélise un navire et que vous êtes maintenant dit que votre navire devrait offrir à hélipad, il n'est pas naturel de dériver votre navire d'un hélipad, (Duh!) À la place, vous devriez avoir Votre navire contient une classe d'hélipad et l'expose via certaines Ship.getHelipad() méthode.

Les années d'âge d'une vieillesse (une décennie il y a une décennie) ont l'habitude de voir l'héritage comme un moyen rapide et facile de regrouper la fonctionnalité, il y avait donc de nombreux exemples du type "navire héritant de Helipad", qui étaient bien sûr très boiteux.

Mais la "composition de faveur sur l'héritage" Dictum a été soigneusement formulée pour indiquer clairement que ce n'est qu'une suggestion, pas une règle. L'auteur du dictum était suffisamment prudent de s'abstenir de dire quelque chose comme "tu shalt jamais Utilisez héritage, seulement Composition". Cela porte essentiellement à l'attention de la communauté d'ingénierie du logiciel le fait que l'héritage a été surutilisé, alors que dans de nombreux cas, la composition produit des conceptions plus claires, élégantes et maintenables que l'héritage.

Donc, essentiellement, la "composition favorable sur l'héritage" Dictum suggère que chaque fois que vous êtes confronté à "hériter ou à composer?" Question, vous devriez penser difficile quelle est la stratégie la plus appropriée et que la plupart des chances sont que la stratégie la plus appropriée s'avère être la composition, pas l'héritage.

Mais comme ce n'est pas une règle, vous devriez également garder à l'esprit qu'il existe de nombreux cas où l'héritage est plus naturel. Si vous utilisez la composition là où vous auriez dû utiliser l'héritage, de nombreux maux vont arriver à votre code.

Pour revenir à l'exemple du navire, si votre navire doit offrir une interface pour interagir avec un FloatingMachine, il est donc plus naturel de le déranger d'un résumé FloatingMachine classe, ce qui pourrait très probablement à son tour être dérivé d'un autre résumé Machine classe.

Voici la règle générale de la réponse à la question de la composition vs héritage:

Ma classe a-t-elle une relation "est une" relation avec l'interface qu'il doit exposer? Si oui, utilisez l'héritage. Sinon, utilisez la composition.

Un navire "est une" machine flottante et une machine flottante "est une" machine ". Donc, l'héritage convient parfaitement à ceux-ci. Mais un navire n'est bien sûr pas un hélipad. Il est donc préférable de composer la fonctionnalité de l'hélipad.

1
Mike Nakis