Il ne s'agit pas de savoir lequel est le meilleur, mais de savoir quand utiliser quoi.
Dans les cas «normaux», une simple question suffit pour savoir si nous avons besoin d'héritage ou d'agrégation.
- Si La nouvelle classe est plus ou moins la classe d'origine. Utilisez l'héritage. La nouvelle classe est désormais une sous-classe de la classe d'origine.
- Si la nouvelle classe doit avoir la classe d'origine. Utilisez l'agrégation. La nouvelle classe a maintenant la classe d'origine en tant que membre.
Cependant, il y a une grande zone grise. Nous avons donc besoin de plusieurs autres astuces.
- Si nous avons utilisé l'héritage (ou si nous prévoyons de l'utiliser) mais que nous n'utilisons qu'une partie de l'interface, ou nous sommes obligés de remplacer beaucoup de fonctionnalités pour garder la corrélation logique. Ensuite, nous avons une grosse odeur désagréable qui indique que nous avons dû utiliser l'agrégation.
- Si nous avons utilisé l'agrégation (ou si nous prévoyons de l'utiliser), mais nous découvrons que nous devons copier presque toutes les fonctionnalités. Ensuite, nous avons une odeur qui pointe dans la direction de l'héritage.
Pour couper court. Nous devrions utiliser l'agrégation si une partie de l'interface n'est pas utilisée ou doit être modifiée pour éviter une situation illogique. Nous n'avons besoin d'utiliser l'héritage que si nous avons besoin de presque toutes les fonctionnalités sans changements majeurs. Et en cas de doute, utilisez l'agrégation.
Une autre possibilité pour, le cas où nous avons une classe qui a besoin d'une partie des fonctionnalités de la classe d'origine, est de diviser la classe d'origine en une classe racine et une sous-classe. Et laissez la nouvelle classe hériter de la classe racine. Mais vous devez faire attention à cela, ne pas créer une séparation illogique.
Ajoutons un exemple. Nous avons une classe «Chien» avec des méthodes: «Eat», «Walk», «Bark», «Play».
class Dog
Eat;
Walk;
Bark;
Play;
end;
Nous avons maintenant besoin d'une classe «Chat», qui a besoin de «Mange», «Marche», «Ronronne» et «Joue». Alors essayez d'abord de l'étendre à partir d'un chien.
class Cat is Dog
Purr;
end;
Regarde, d'accord, mais attendez. Ce chat peut aboyer (les amoureux des chats me tueront pour ça). Et un chat qui aboie viole les principes de l'univers. Nous devons donc remplacer la méthode Bark afin qu'elle ne fasse rien.
class Cat is Dog
Purr;
Bark = null;
end;
Ok, ça marche, mais ça sent mauvais. Alors essayons une agrégation:
class Cat
has Dog;
Eat = Dog.Eat;
Walk = Dog.Walk;
Play = Dog.Play;
Purr;
end;
Ok, c'est bien. Ce chat n'aboie plus, pas même silencieux. Mais il a toujours un chien interne qui veut sortir. Essayons donc la solution numéro trois:
class Pet
Eat;
Walk;
Play;
end;
class Dog is Pet
Bark;
end;
class Cat is Pet
Purr;
end;
C'est beaucoup plus propre. Pas de chiens internes. Et les chats et les chiens sont au même niveau. Nous pouvons même introduire d'autres animaux pour étendre le modèle. À moins que ce ne soit un poisson ou quelque chose qui ne marche pas. Dans ce cas, nous devons à nouveau refactoriser. Mais c'est quelque chose pour une autre fois.