Introdução

Primeiramente é necessário entender o que é Composição e o que é Herança. Composição e Herança são dois mecanismos para reutilizar funcionalidades.

A herança sempre foi considerada uma ferramenta básica de extensão e reuso de funcionalidade e se dá estendendo atributos e métodos de uma classe.

Segue abaixo um diagrama de classe exemplificando o uso de Herança.

Exemplo de Herança

Figura 1: Exemplo de Herança

O diagrama de classe acima seria implementado em Java conforme o código na listagem abaixo:

Listagem 1: Exemplo de herança de classes em Java.

public class Animal {

}

public class Cachorro extends Animal {

}

public class Gato extends Animal {
	
}

Acima tem-se a definição de Animal que é a superclasse e das classes Cachorro e Gato que herdam tudo da classe Animal. Neste exemplo na classe Animal não tem nada, porém se tivesse atributos ou métodos eles seriam Herdados pelas suas subclasses Cachorro e Gato. Vale salientar que devemos atentar para a visibilidade dos atributos e métodos no caso da Herança, lembre-se que tudo que é privado não é herdado, pois pertence unicamente à classe detentora.

Na herança temos o conceito de uma Classe Pai, Classe Base ou Superclasse (todas essas nomenclaturas denotam a mesma coisa) que é a classe que foi herdada pelas subclasses. A Classe Filha ou Subclasse é a classe que herda da classe Pai. Outros dois conceitos que temos na Herança é a Generalização onde se obtém similaridades entre classes e dessa forma define-se novas classes. As classes mais genéricas são as classes Pai. E a Especialização é onde Identifica-se atributos e métodos não correspondentes entre classes distintas colocando-os na classe filha. Ou seja, quando se tem similaridades entre as classes procura-se generalizá-las levando suas similaridades para a classe pai onde as classes filhas irão herdar essa similaridade. Por outro lado quando temos atributos e métodos não correspondentes nas classes filhas colocamos essas não correspondências nas classes filhas mais específicas que irão usar esses atributos e métodos. Normalmente na Herança usamos o termo "É um". Por exemplo, podemos dizer que um carro É UM automóvel, portanto temos que um carro herda os atributos e métodos de um automóvel, assim como um caminhão também É UM automóvel. Neste exemplo temos uma hierarquia de herança onde um Carro e um Caminhão herdam atributos e métodos comuns entre eles que estão definidos numa superclasse Automovel. Para o exemplo acima a herança também é válida pois Cachorro É UM Animal e Gato também É UM Animal.

A composição por sua vez estende uma classe pela delegação de trabalho para outro objeto. Na composição ao invés de codificarmos um comportamento estaticamente, como é feito com o uso de herança, definimos pequenos comportamentos padrão e usamos composição para definir comportamentos mais complexos. Na composição agora podemos mudar a associação entre classes em tempo de execução, assim um objeto pode assumir mais de um comportamento.

O Diagrama de classe abaixo mostra um exemplo de composição onde um Sistema é composto de uma Pessoa.

Exemplo de composição

Figura 2: Exemplo de composição

O diagrama de classe acima seria implementado em Java conforme o código na listagem abaixo:

Listagem 2: Exemplo de composição em Java.

public class Sistema {

	Pessoa pessoa = new Pessoa();
	
}

public class Pessoa {
	
}

Na composição temos uma instância da classe existente sendo usada como componente da outra classe. A composição usa o termo TEM UM. Por exemplo, podemos dizer que um carro TEM UM pneu, neste exemplo temos a definição de uma composição.

Benefícios e Problemas da Herança

Um dos benefícios da Herança é que ela captura o que é comum e o isola daquilo que é diferente, além disso, a herança é vista diretamente no código até mesmo devido a sua natureza estática.

Entre os problemas da Herança está o fraco encapsulamento entre classes e subclasses e o forte acoplamento entre elas onde ao mudar uma superclasse pode afetar todas as subclasses além de violar o princípio básico de projeto OO em que devemos ter sempre um baixo acoplamento entre as classes. Além disso, algumas vezes um objeto precisa ser de uma classe diferente em momentos diferentes o que não é possível com a herança, pois o código não pode sofrer alterações facilmente em tempo de execução, portanto tem-se que a herança é um relacionamento estático.

Benefícios e Problemas da Composição

A grande vantagem da Composição é que o comportamento pode ser escolhido em tempo de execução em vez de estar amarrado em tempo de compilação. Além disso, os objetos que foram instanciados e estão contidos na classe que os instanciou são acessados somente através de sua interface seguindo assim o princípio de programar para uma interface e não para uma implementação. A composição também apresenta uma menor dependência de implementações e temos cada classe focada em apenas uma tarefa seguindo outro principio da responsabilidade única. Por fim, a composição também tem um bom encapsulamento onde os detalhes internos dos objetos instanciados não são visíveis.

A grande desvantagem é que um software muito dinâmico e parametrizado é mais difícil de entender do que software mais estático.

Quando usar Composição ou Herança

De forma geral prefira utilizar sempre a Composição em relação à Herança, no entanto pode-se definir algumas regras para identificar quando podemos usar a Herança de forma que não tenhamos os problemas que ela acarreta. Utiliza-se a herança se uma instância de uma classe Filha nunca precisar tornar-se um objeto de outra classe, se a hierarquia de herança representar um relacionamento "É um" e não um relacionamento "Tem um", se deseja-se ou precisa-se realizar alterações globais para as suas classes filhas alterando uma classe Pai, ou então quando a classe filha estender ao invés de substituir total ou parcialmente as responsabilidades da classe Pai.

Conclusão

De forma geral a herança deve ser pouco utilizada. Atualmente a composição é considerada muito superior à herança na maioria dos casos pois entre as suas principais vantagens a composição permite mudar a associação entre classes em tempo de execução, os objetos podem assumir mais de um comportamento, os projetos são mais simples e reutilizáveis, além de descartar os problemas envolvendo a herança como o acoplamento entre as classes e outros problemas discutidos. A composição é utilizada em diversos Padrões de Projetos comprovando assim a sua grande utilidade e uso no desenvolvimento de projetos melhores.

Bibliografia

  • Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra. Head First Design Patterns. O'Reilly Media, 2004.