C# - Acoplamento entre classes : herança x composição - II
Hoje vamos continuar a recordar o que é o acoplamento entre classes e quais são os seus efeitos em um projeto de software.

Continuando a primeira parte do artigo vamos fazer uma comparação prática entre herança e composição.

A seguir vamos criar um projeto C# do tipo Console na plataforma .NET Core para mostrar a diferença.

recursos usados:

  • Visual Basic 2019 Community Edition

Criando o projeto C# no VS 2019

Crie um projeto Console do tipo .NET Core com o seguinte nome para a Solution: CShp_Acoplamento, e,  o seguinte nome para o projeto :  CShp_Acoplamento_Heranca:

No projeto CShp_Acoplamento_Heranca vamos criar duas classes A e B onde a classe B vai herdar da classe A.

1- Classe A

2- Classe B

No código acima a Classe B possui um forte acoplamento com a classe A ditado pela herança.

Se houver alguma mudança na superclasse A o código da classe B 'vai quebrar'.

Suponha que precisamos alterar a classe A incluindo um novo parâmetro do tipo string no método MetodoA() :

Essa alteração feita na classe A vai fazer com que a classe B não compile mais :


Portanto, esse tipo de dependência pode subir para qualquer nível e pode ser muito perigoso, e  qualquer alteração feita na superclasse vai se propagar na hierarquia da herança.

Como podemos minimizar esse problema usando composição ?

Usando a composição

Vamos agora incluir outro projeto na solução chamado Cshp_Acoplamento_Composicao via menu File->Add Project;

A seguir vamos definir esse projeto como o projeto padrão : Set as Startup Project

A seguir vamos criar as classes A e B no projeto, sendo que agora não vamos usar herança mas composição.

1- Classe A

2- Classe B

Agora estamos criando uma referência da classe A na classe B e invocando o método da classe A através da instância da classe A.

Assim reduzimos o acoplamento e tanto a Superclasse (A) como a classe filha(B) agora são mais independentes uma da outra e podem fazer alterações mais adaptáveis do que as realizadas na herança.

Outra vantagem desta abordagem é que se o estado da instância A não for conhecido, ele poderá ser facilmente mockado(*) usando alguns dados de teste e todos os métodos poderão ser testados.

Nota(*): Veja o meu artigo:  .NET - Usando MOQ em testes unitários - I - Macoratti.net

Na herança isso não é possível pois dependemos da superclasse para obter o estado da instância e executar qualquer método.

Percebemos assim que a herança, embora seja um recurso poderoso, deve ser usado com muito cuidado.

Mas Deus escolheu as coisas loucas deste mundo para confundir as sábias; e Deus escolheu as coisas fracas deste mundo para confundir as fortes;
E Deus escolheu as coisas vis deste mundo, e as desprezíveis, e as que não são, para aniquilar as que são;
Para que nenhuma carne se glorie perante ele.

1 Coríntios 1:27-29

"Mas Deus escolheu as coisas loucas deste mundo para confundir as sábias; e Deus escolheu as coisas fracas deste mundo para confundir as fortes;
E Deus escolheu as coisas vis deste mundo, e as desprezíveis, e as que não são, para aniquilar as que são;
Para que nenhuma carne se glorie perante ele."

1 Coríntios 1:27-29

Referências:


José Carlos Macoratti