No se trata de cuál es el mejor, sino de cuándo usar qué.
En los casos "normales", una simple pregunta es suficiente para averiguar si necesitamos herencia o agregación.
- Si La nueva clase es más o menos como la clase original. Usar herencia. La nueva clase ahora es una subclase de la clase original.
- Si la nueva clase debe tener la clase original. Usar agregación. La nueva clase tiene ahora la clase original como miembro.
Sin embargo, hay una gran área gris. Entonces necesitamos varios otros trucos.
- Si hemos usado la herencia (o planeamos usarla) pero solo usamos parte de la interfaz, o nos vemos obligados a anular una gran cantidad de funcionalidades para mantener la correlación lógica. Luego tenemos un gran olor desagradable que indica que tuvimos que usar la agregación.
- Si hemos usado 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 acortarlo. Deberíamos usar la agregación si parte de la interfaz no se usa o si tiene que cambiarse para evitar una situación ilógica. Solo necesitamos usar la herencia, si necesitamos casi toda la funcionalidad sin cambios importantes. Y en caso de duda, use la agregación.
Otra posibilidad para el caso de que tengamos 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 debe tener cuidado con esto, no para crear una separación ilógica.
Agreguemos un ejemplo. Tenemos una clase 'Perro' con métodos: 'Comer', 'Caminar', 'Ladrar', 'Jugar'.
class Dog
Eat;
Walk;
Bark;
Play;
end;
Ahora necesitamos una clase 'Gato', que necesita 'Comer', 'Caminar', 'Ronronear' y 'Jugar'. Así que primero intenta extenderlo desde un perro.
class Cat is Dog
Purr;
end;
Parece, está 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. Por lo tanto, debemos anular el método Bark para que no haga nada.
class Cat is Dog
Purr;
Bark = null;
end;
Ok, esto funciona, pero huele mal. Entonces intentemos una agregación:
class Cat
has Dog;
Eat = Dog.Eat;
Walk = Dog.Walk;
Play = Dog.Play;
Purr;
end;
Ok, esto es lindo Este gato ya no ladra, ni siquiera calla. Pero aún tiene un perro interno que quiere salir. Entonces intentemos 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. No hay perros internos. Y los gatos y los perros están al mismo nivel. Incluso podemos introducir otras mascotas para ampliar el modelo. A menos que sea un pez, o algo que no camina. En ese caso, nuevamente necesitamos refactorizar. Pero eso es algo para otro momento.