La composition est lorsqu'une classe offre des fonctionnalités en instanciant une classe (éventuellement interne) qui implémente déjà cette fonctionnalité, au lieu d'hériter de cette classe.
Ainsi, par exemple, si vous avez une classe qui modélise un navire et qu'on vous dit maintenant que votre navire devrait offrir un héliport, il n'est pas naturel de dériver votre navire d'un héliport, (duh!) À la place, vous devriez avoir votre vaisseau contient une classe d'héliport et l'expose via une Ship.getHelipad()
méthode.
Autrefois (il y a une dizaine d'années), les gens considéraient l'héritage comme un moyen rapide et facile d'agréger les fonctionnalités, il y avait donc de nombreux exemples du type "navire héritant de l'héliport", qui étaient, bien sûr, très boiteux.
Mais le dicton "Favoriser la composition plutôt que l'héritage" a été soigneusement rédigé de manière à indiquer clairement qu'il ne s'agit que d'une suggestion, et non d'une règle. L'auteur du dicton a fait preuve de suffisamment de prudence pour s'abstenir de dire quelque chose comme "tu n'utiliseras jamais l' héritage, seulement la composition". Cela porte essentiellement à l'attention de la communauté du génie 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, le dicton "Favoriser la composition sur l'héritage" suggère que chaque fois que vous êtes confronté au "hériter ou composer?" question, vous devriez réfléchir sérieusement à la stratégie la plus appropriée, et que la plupart des chances sont que la stratégie la plus appropriée se révélera être la composition, pas l'héritage.
Mais comme ce n'est pas une règle, vous devez é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 arriveront dans votre code.
Pour revenir à l'exemple du vaisseau, si votre vaisseau a besoin d'offrir une interface pour interagir avec un FloatingMachine
, alors il est plus naturel de le dériver d'une FloatingMachine
classe abstraite , qui pourrait très probablement dériver à son tour d'une autre Machine
classe abstraite .
Voici la règle générale pour la réponse à la question de la composition par rapport à l'héritage:
Ma classe a-t-elle une relation "est une" avec l'interface qu'elle 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. L'héritage est donc parfaitement bien pour ceux-là. Mais un navire n'est pas, bien sûr, un héliport. Il est donc préférable de composer la fonctionnalité de l'héliport.