Como agregar responsabilidade a Objetos individuais, em tempo de execução, independente de sua Classe?
Utilizando Decorator Pattern.
Os Decoradores oferecem uma alternativa simples e flexível ou uso de subclasses para extensão de funcionalidades.
Para mim, Decorador é um dos mais importantes padrões de design. Infelizmente esse padrão quase nunca é utilizado, pelo menos nos projetos que vi nos últimos anos, independentemente da linguagem de programação utilizada.
Por que?
Não tenho uma resposta exata, mas suponho que o motivo do não uso de Decoradores seja devido a escolha “natural” de utilizarmos Herança de Classes para estender funcionalidades.
Aprendemos que a Orientação a Objetos tem 3 pilares: Herança, Encapsulamento e Polimorfismo.
Herança de Classe é utilizada para estender funcionalidades, implementando uma nova Classe que herda as funcionalidades da primeira e de toda uma hierarquia. Então você acha que usar Herança sempre será a escolha mais correta para extensão de funcionalidades?
Eu acho que não. Em 90~95% dos casos, eu utilizo Decoradores e Composição de Objetos.
Um Decorador oferece uma abordagem do tipo "use quando for necessário” para adição de responsabilidades. Em vez de tentar suportar todas as características previsíveis em uma Classe complexa e customizada, você pode definir uma Classe simples e acrescentar funcionalidade de modo incremental com objetos Decoradores.
Decoradores são tão simples de implementar como Herança, mas traz mais benefícios.
- Você não precisa prever o futuro utilizando Decoradores. Utilizando Herança você tem que se preocupar com a hierarquia das Classes desde o início, desde a Classe mais básica até a mais específica, como se pudesse prever o futuro;
- Evita Classes sobrecarregadas de características e funcionalidades;
- Classes pequenas e coesas;
Exemplos de código?
- Parte do código de um projeto em produção que utiliza Decoradores para consumir um WebService, aqui.
- Implementação de um Log com Decoradores para memória, arquivo, banco de dados e e-mail, aqui;
- Utilizando a Classe
TEmployeeSalaryWithCommission
como Decorador deTEmployeeSalary
, aqui;
Até logo.