No es una cuestión de cuál es el mejor, sino de cuándo utilizar qué.
En los casos "normales" una simple pregunta es suficiente para saber si necesitamos herencia o agregación.
- Si la nueva clase es más o menos como la clase original. Usa la herencia La nueva clase ahora es una subclase de la clase original.
- Si la nueva clase debe tener la clase original. Use la agregación. La nueva clase ahora tiene la clase original como miembro.
Sin embargo, hay una gran área gris. Entonces necesitamos muchos otros trucos.
- Si hemos utilizado la herencia (o tenemos la intención de usarlo) pero sólo utilizar parte de la interfaz, o estamos obligados a anular un montón de funcionalidades para mantener la correlación lógica. Entonces tenemos un gran olor desagradable que indica que tuvimos que usar la agregación.
- Si usamos la agregación (o planeamos usarla) pero descubrimos que necesitamos copiar casi toda la funcionalidad. Entonces tenemos un olor que apunta en la dirección de la herencia.
Para abreviar. Deberíamos usar la agregación si parte de la interfaz no se usa o debe modificarse para evitar una situación ilógica. Solo necesitamos usar herencia, si necesitamos casi toda la funcionalidad sin grandes cambios. Y cuando tenga dudas, use Agregación.
Otra posibilidad para, si tenemos una clase que necesita parte de la funcionalidad de la clase original, es dividir la clase original en una clase raíz y una subclase. Y deje que la nueva clase herede de la clase raíz. Pero deberías cuidarte con esto, no para crear una separación ilógica.
Permite agregar un ejemplo. Tenemos una clase 'Perro' con métodos: 'comer', 'caminar', 'ladrar', 'jugar'.
class Dog
Eat;
Walk;
Bark;
Play;
end;
Ahora necesitamos un clase 'Gato', que necesita 'Coma', 'Walk', 'Purr', y 'Play'. Entonces primero intenta extenderlo desde un perro.
class Cat is Dog
Purr;
end;
Parece, bien, pero espera. Este gato puede ladrar (los amantes de los gatos me matarán por eso). Y un gato ladrando viola los principios del universo. Entonces debemos anular el método de Bark para que no haga nada.
class Cat is Dog
Purr;
Bark = null;
end;
Ok, esto funciona, pero huele mal. Intentemos una agregación:
class Cat
has Dog;
Eat = Dog.Eat;
Walk = Dog.Walk;
Play = Dog.Play;
Purr;
end;
Ok, esto es bueno. Este gato ya no ladra, ni siquiera en silencio. Pero todavía tiene un perro interno que quiere salir. Así que vamos a probar la solución número tres:
class Pet
Eat;
Walk;
Play;
end;
class Dog is Pet
Bark;
end;
class Cat is Pet
Purr;
end;
Esto es mucho más limpio. Sin perros internos. Y los gatos y los perros están en el mismo nivel. Incluso podemos presentar otras mascotas para ampliar el modelo. A menos que sea un pez, o algo que no camine. En ese caso, nuevamente tenemos que refactorizar. Pero eso es algo para otro momento.
Buena pregunta, desafortunadamente no tengo suficiente tiempo ahora. –
Una buena respuesta es mejor que una más rápida ... Voy a ver mi propia pregunta, así que te votaré al menos :-P –
Se ha expandido ahora ;-). –