Pourquoi préférer la composition au cours de l'héritage? Ce compromis, il y a pour chaque approche? Quand devriez-vous choisir d'héritage sur la composition?
Réponses
Trop de publicités?Préférez la composition au cours de l'héritage comme il est plus malléable, facile à modifier par la suite, mais n'utilisez pas de composer toujours. Avec la composition, il est facile pour un changement de comportement à la volée avec l'Injection de Dépendances / Setters. L'héritage est plus rigide que la plupart des langues ne permet pas de tirer de plus d'un type.. Si le goose est plus ou moins cuit une fois que vous dériver de la Classe A.
Mon test à l'acide pour le ci-dessus est:
- Ne TypeB souhaitez exposer l'interface complète (toutes les méthodes publiques ni moins) de TypeA tels que TypeB peut être utilisé là où TypeA est prévu? Indique L'Héritage.
par exemple, Un Cessna biplan, va exposer à l'interface complète d'un avion, si pas plus. De sorte que le rend apte à tirer de l'Avion.
- Ne TypeB ne voulez seulement certains/une partie du comportement exposés par TypeA? Indique un besoin pour une Composition.
par exemple, Un Oiseau peut-être besoin que la mouche comportement d'un Avion. Dans ce cas, il est logique d'en extraire une interface / classe / les deux et en faire un membre de ces deux classes.
Mise à jour: reviens à ma réponse et il semble maintenant qu'il est incomplet sans la mention expresse de Barbara Liskov du Principe de Substitution de Liskov comme un test pour " Devrais-je être héritent de ce type?'
Pense de confinement comme a une relation. Une voiture "a un moteur, une personne "a un" nom", etc.
Penser à l'héritage comme un est une relation. Une voiture "qui est" un véhicule, une personne "est un" mammifère, etc.
Je ne vais pas prendre le crédit pour cette approche. Je l'ai pris directement à partir de la Deuxième Édition de Code Complet par Steve McConnell, Section 6.3.
Si vous comprenez la différence, c'est plus facile à expliquer.
Code De Procédure
Un exemple de ceci est PHP sans l'utilisation de classes (en particulier avant de PHP5). Toute logique est encodé dans un jeu de fonctions. Vous pouvez inclure d'autres fichiers contenant les fonctions d'assistance et ainsi de suite et la conduite de vos affaires de la logique par le passage des données autour de dans les fonctions. Ceci peut être très difficile à gérer, car la demande augmente. PHP5 essaie de remédier à cela en offrant plus de la conception orientée objet.
L'héritage
Cela encourage l'utilisation des classes. L'héritage est l'un des trois principes de OO design (héritage, polymorphisme, encapsulation).
class Person {
String Title;
String Name;
Int Age
}
class Employee : Person {
Int Salary;
String Title;
}
C'est l'héritage au travail. L'Employé "est" une Personne ou hérite de Personne. Toutes les relations d'héritage sont de type "est-un" relations". Employé également ombres le Titre de propriété de la Personne, sens de l'Employé.Le titre sera de retour le Titre de l'Employé n'est pas la Personne.
Composition
La Composition est privilégié par rapport à l'héritage. Pour faire très simple, vous auriez:
class Person {
String Title;
String Name;
Int Age;
public Person(String title, String name, String age) {
this.Title = title;
this.Name = name;
this.Age = age;
}
}
class Employee {
Int Salary;
private Person person;
public Employee(Person p, Int salary) {
this.person = p;
this.Salary = salary;
}
}
Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);
La Composition est généralement "a" ou "un" de la relation. Ici, l'Employé de classe a d'une Personne. Il n'hérite pas d'une Personne mais il récupère à la Personne objet passé en elle, c'est pourquoi il "a une" Personne".
La Composition au cours de l'Héritage
Maintenant, imaginons que vous vouliez créer un type de Gestionnaire si vous vous retrouvez avec:
class Manager : Person, Employee {
...
}
Cet exemple fonctionne correctement, cependant, que si la Personne et Employé à la fois déclarée Title
? Devrait Manager.Le titre de retour de "directeur des Opérations" ou "Monsieur"? En vertu de la composition de cette ambiguïté est mieux géré:
Class Manager {
public Title;
public Manager(Person p, Employee e)
{
this.Title = e.Title;
}
}
Le Gestionnaire d'objet est composé comme un Employé et une Personne. Le Titre comportement est pris de l'employé. Cette explicites composition supprime l'ambiguïté entre autres choses, et vous rencontrerez moins de bugs.
Avec tous les indéniables avantages fournis par l'héritage, voici quelques-uns de ses inconvénients.
Les inconvénients de l'Héritage:
- Vous ne pouvez pas changer la mise en œuvre hérité de super-classes au moment de l'exécution (évidemment parce que l'héritage est défini au moment de la compilation).
- L'héritage expose une sous-classe pour les détails de l'un de ses parents de la classe de mise en œuvre, c'est pourquoi il est souvent dit que l'héritage des pauses d'encapsulation (dans un sens que vous avez vraiment besoin de se concentrer sur les interfaces seulement pas mise en œuvre, de sorte que la réutilisation, par sous que le classement n'est pas toujours de préférence).
- Le couplage fournis par l'héritage fait de la mise en œuvre d'une sous-classe très lié à la mise en œuvre d'une classe super que tout changement dans le parent de la mise en œuvre sera la force de la classe de sous pour changer.
- Excessive de la réutilisation par des sous-classing peut faire de l'héritage de la pile de façon très profonde et très déroutant.
D'autre part une composition d'Objet est définie au moment de l'exécution à travers des objets d'acquérir des références à d'autres objets. Dans un tel cas, ces objets ne seront jamais en mesure d'atteindre les uns les autres protégés de données (pas de briser l'encapsulation) et sera forcé de se respecter les uns les autres de l'interface. Et dans ce cas également, la mise en œuvre des dépendances-être beaucoup moins que dans le cas de l'héritage.
Un autre, très pragmatique de la raison, de préférer la composition au cours de l'héritage a à voir avec votre modèle de domaine, et de la cartographie à une base de données relationnelle. C'est vraiment dur à la carte de l'héritage du modèle SQL (vous vous retrouvez avec toutes sortes de hacky solutions de contournement, comme la création de colonnes qui ne sont pas toujours utilisé, à l'aide de points de vue, etc). Certains ORMLs d'essayer de traiter avec cela, mais il obtient toujours compliqué rapidement. La Composition peut être facilement modélisé par une relation de clé étrangère entre les deux tables, mais l'héritage est beaucoup plus difficile.