OOP - Herança x Composição
O paradigma da Programação Orientação a objetos - OOP - traz muitos conceitos novos e, para quem vem do paradigma procedural usando as linguagens estruturadas e do desenvolvimento orientado ao banco de dados, às vezes muitos desses conceitos podem não ser bem compreendidos. |
Vamos iniciar recordando a definição de programação procedural:
O termo
Programação procedural (ou programação procedimental) é as vezes
utilizado como sinônimo de Programação imperativa (Paradigma de programação
que especifica os passos que um programa deve seguir para alcançar um estado
desejado), mas o termo pode se referir a um paradigma de
programação baseado no conceito de chamadas a procedimento.
Procedimentos,
também conhecidos como rotinas, sub-rotinas, métodos, ou funções (que não
devem ser confundidas com funções matemáticas, mas são similares àquelas
usadas na programação funcional) simplesmente contém um conjunto de passos
computacionais a serem executados. Um dado procedimento pode ser chamado a
qualquer hora durante a execução de um programa, inclusive por outros
procedimentos ou por si mesmo. |
Apenas para ilustrar, abaixo temos uma tabela comparando as características básicas do paradigma OOP e do procedural:
Programação Orientada a Objetos | Programação Estruturada |
Métodos | Procedimentos e funções |
Instâncias de variáveis | Variáveis |
Mensagens | Chamadas a procedimentos e funções |
Classes | Tipos de dados definidos pelo usuário |
Herança | - |
Polimorfismo |
Se você quer construir um código limpo , legível , escalável e reutilizável usando os conceitos da OOP terá que ter uma compreensão sólida dos principais conceitos deste paradigma.
Como o C# e VB .NET são linguagens Orientada a Objetos(OO), podemos usá-las para criar projetos dentro do paradigma OOP.
Este artigo procurar focar dois mecanismos básicos usados para reutilizar código muito utilizados na programação orientada a objetos (POO) : a herança e a composição.
Qual seria melhor ? Usar composição ou usar herança ?
Vou responder a pergunta e depois explicar...
Resposta:
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.
Na verdade a herança deve ser usada com cuidado e apenas em algumas situações.
Estranhou a resposta ???
Você achava que herança era o supra-sumo dos recursos do arsenal das linguagens OO ??
Se você pensava assim estava enganado...
Então senta que o leão é manso...
Obs: Lembrando que nem a linguagem C# nem a VB .NET suportam herança múltipla; assim uma classe pode herdar de apenas uma única classe.
Ah!! Outro detalhe, eu estou considerando apenas herança de implementação e não estou entrando em detalhes em herança de Interface. Ok ?
Uma rápida revisão de conceitos
Herança
Exemplo:
Pessoa -
classe Pai, classe Base ou Super Classe
- A classe Pessoa
é a classe genérica; -
PessoaFisica É uma pessoa; |
Implementação:
Namespace Herança |
namespace Herança { public class Pessoa { private String nome; private String Endereco; } public class PessoaFisica : Pessoa { private String CPF; public PessoaFisica() {} } public class PessoaJuridica : Pessoa { private String CNPJ; public PessoaJuridica() { } } } |
VB .NET | C# |
Composição
Exemplo
Pedido -
Classe que contém uma instância da classe Itens; - Um pedido TEM UM Item; |
Implementação
Public Class Pedido
Private i As Itens
Public Sub New()
i = New Itens()
End Sub
End Class
Public Class Itens
Public Sub New()
End Sub
End Class
|
public
class Pedido { private Itens i; public Pedido( ) { i = new Itens(); } } public class Itens { public Itens( ){} } |
VB .NET | C# |
Mas porque devemos mesmos dar preferência ao usa da composição a usar herança ?
Usando herança:
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;
Usando composição:
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;
Percebemos que a herança viola dois conceitos básicos que sempre devemos aplicar em nosso código enquanto que a composição naturalmente nos leva a usar tais conceitos.
Mas então eu nunca devo usar herança ??? (Nunca é uma palavra que nós mortais deveríamos pronunciar com muito cuidado....)
Não existe um mandamento para nunca usar herança, mas podemos definir algumas regras para identificar quando podemos usá-la de forma não ter os problemas que ela acarreta:
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" e não um relacionamento "Tem
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;
Obs: Cuidado com a aplicação do princípio "É Um" às vezes ele nos leva a cometer erros que percebemos só depois de olharmos o código. (Vide a violação do princípio LSP)
Eu sei é apenas OOP , mas eu gosto...
"E Jesus lhes disse: Eu sou o pão da vida: aquele que vem a mim não terá fome; e quem crê em mim nunca terá sede." (João 6:35)
Referências:
http://www.lisha.ufsc.br/teaching/sce/ine5612-2001-2/work/wegner.html
Boas Práticas - O padrão inversão de controle (IoC) - Macoratti.net
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#