Não é uma questão de qual é o melhor, mas de quando usar o quê.
Nos casos "normais", basta uma pergunta simples para descobrir se precisamos de herança ou agregação.
- Se A nova classe é mais ou menos como a classe original. Use herança. A nova classe agora é uma subclasse da classe original.
- Se a nova classe deve ter a classe original. Use agregação. A nova classe agora tem a classe original como membro.
No entanto, existe uma grande área cinzenta. Então, precisamos de vários outros truques.
- Se usamos herança (ou pretendemos usá-la), mas usamos apenas parte da interface, ou somos forçados a substituir muitas funcionalidades para manter a correlação lógica. Temos um cheiro desagradável que indica que tivemos que usar agregação.
- Se usamos agregação (ou pretendemos usá-la), mas descobrimos que precisamos copiar quase toda a funcionalidade. Então temos um cheiro que aponta na direção da herança.
Para encurtar. Devemos usar a agregação se parte da interface não for usada ou precisar ser alterada para evitar uma situação ilógica. Só precisamos usar herança, se precisarmos de quase toda a funcionalidade sem grandes alterações. E em caso de dúvida, use Agregação.
Outra possibilidade para o caso de termos uma classe que precisa de parte da funcionalidade da classe original é dividir a classe original em uma classe raiz e uma subclasse. E deixe a nova classe herdar da classe raiz. Mas você deve tomar cuidado com isso, para não criar uma separação ilógica.
Vamos adicionar um exemplo. Temos uma classe 'Dog' com métodos: 'Eat', 'Walk', 'Bark', 'Play'.
class Dog
Eat;
Walk;
Bark;
Play;
end;
Agora precisamos de uma classe 'Gato', que precisa de 'Comer', 'Andar', 'Purr' e 'Brincar'. Então, primeiro tente estendê-lo de um cão.
class Cat is Dog
Purr;
end;
Parece, tudo bem, mas espere. Este gato pode latir (os amantes de gatos me matam por isso). E um gato latindo viola os princípios do universo. Portanto, precisamos substituir o método Bark para que ele não faça nada.
class Cat is Dog
Purr;
Bark = null;
end;
Ok, isso funciona, mas cheira mal. Então, vamos tentar uma agregação:
class Cat
has Dog;
Eat = Dog.Eat;
Walk = Dog.Walk;
Play = Dog.Play;
Purr;
end;
Ok, isso é legal. Este gato não late mais, nem mesmo em silêncio. Mas ainda tem um cachorro interno que quer sair. Então, vamos tentar a solução número três:
class Pet
Eat;
Walk;
Play;
end;
class Dog is Pet
Bark;
end;
class Cat is Pet
Purr;
end;
Isso é muito mais limpo. Não há cães internos. E gatos e cães estão no mesmo nível. Podemos até introduzir outros animais de estimação para estender o modelo. A menos que seja um peixe ou algo que não anda. Nesse caso, precisamos novamente refatorar. Mas isso é algo para outra hora.