C# - Herança ou Composição ?


Hoje vamos tentar responder à pergunta : "Devo usar herança ou composição ?"

Herança e composição são duas técnicas de programação usadas para estabelecer relacionamentos entre classes e objetos. Enquanto a herança deriva uma classe de outra, a composição define uma classe como a soma de suas partes.


As classes e objetos criados por herança são fortemente acoplados porque alterar a classe base ou classe pai em um relacionamento de herança corre o risco de quebrar seu código.

As classes e objetos criados por meio da composição são fracamente acoplados, o que significa que você pode alterar mais facilmente as partes do componente sem quebrar seu código.

Em geral usar composição traz mais vantagens do que utilizar herança.  Os projetos tendem a ser mais simples e reutilizáveis em se favorecendo a composição ao invés da herança.

Como o código fracamente acoplado oferece mais flexibilidade, muitos desenvolvedores aprenderam que a composição é uma técnica melhor que a herança, mas a realidade não é tão simples assim e existem muitos cenários e fatores que atuam de forma que escolher entre herança e composição não é tão simples.

Quando devo usar herança ?

Na programação orientada a objetos, podemos usar a herança quando sabemos que existe um relacionamento do tipo "é um" entre uma classe filha e sua classe pai.

Exemplos:

  1. Uma pessoa é humana
  2. Um cachorro é um animal
  3. Um carro é um veículo

Em cada exemplo, temos o filho ou subclasse é uma versão especializada do pai ou superclasse. Herdar de uma classe pai é um exemplo de reutilização de código.

Vejamos um exemplo onde carro herda de um veículo:

1- Classe Pai ou classe base

1- Classe Filha ou subclasse


Agora vamos criar uma instância da classe derivada e ver a herança funcionando:

Abaixo temos o resultado:

Então, quando você considerar usar herança pergunte a sim mesmo se a classe filha realmente é uma versão mais especializada da classe pai.

No exemplo temos que um carro é um tipo de veículo , assim o relacionamento de herança faz sentido.

Mas considere que quando você usa herança você esta tendo os seguintes problemas:

1- Ao usar herança estamos violando um dos pilares da orientação a objetos: o encapsulamento, visto que os detalhes da implementação da classe Pai são expostos nas classes Filhas;
2- Ao usar herança estamos violando um dos princípios básicos das boas práticas de programação : manter o acoplamento entre as classe fraco, visto que as classes filhas estão fortemente acopladas à classe Pai e alterar uma classe Pai pode afetar todas as classes Filhas;
3- As implementações herdadas da classe Pai pelas classes Filhas não pode ser alteradas em tempo de execução;

Quando devo usar Composição ?

Na programação orientada a objetos, podemos usar a composição nos casos em que um objeto "possui" (ou faz parte de) outro objeto. Alguns exemplos seriam:

  1. Um carro tem uma bateria (a bateria faz parte de um carro).
  2. Uma pessoa tem um pulmão (um pulmão faz parte de uma pessoa).
  3. Uma casa tem uma sala de jantar (uma sala de jantar faz parte de uma casa).

Para entender melhor esse tipo de relacionamento, considere a composição de uma casa:

1- A classe pai

A seguir temos o código das classes Quarto , Cozinha e Banheiro que compõe a classe Casa :

Nesse caso, sabemos que uma casa tem um quarto, uma cozinha e um banheiro, e, assim podemos usar os objetos das classes Quarto, Cozinha e Banheiro  na composição de uma casa.

Agora mostrando um exemplo de uso teremos:

Com o seguinte resultado:

Assim na composição temos que :

1- Os objetos que foram instanciados e estão contidos na classe que os instanciou são acessados somente através de sua interface;
2- A composição pode ser definida dinamicamente em tempo de execução pela obtenção de referência de objetos a objetos de do mesmo tipo;
3- A composição apresenta uma menor dependência de implementações;
4- Na composição temos cada classe focada em apenas uma tarefa (princípio SRP);
5- Na composição temos um bom encapsulamento visto que os detalhes internos dos objetos instanciados não são visíveis;

Mas então eu nunca devo usar herança ???
(Nunca é uma palavra que nós mortais deveríamos pronunciar com muito cuidado....)

Então , considere a utilização da herança se...:

- A classe Filha expressar "um tipo especial de" e não "ser um papel desempenhado por";
- Uma instância de uma classe Filha NUNCA precisar tornar-se um objeto de outra classe;
- A classe filha estender ao invés de substituir total ou parcialmente as responsabilidades da classe Pai;
- A sua hierarquia de herança representar um relacionamento "É um";
- Você desejar ou precisar realizar alterações globais para as suas classes filhas alterando uma classe Pai;
- Você precisar aplicar a mesma classe e métodos a diferente tipos de dados;

E estamos conversados...

Pegue o projeto completo aqui:  CShp_HerancaComposicao.zip

Disse Jesus: "Se, pois, o Filho vos libertar, verdadeiramente sereis livres."
João 8:36


Referências:


José Carlos Macoratti