O padrão de projeto Decorator tem suas raízes na programação orientada a objetos e foi formalmente descrito por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides no livro "Design Patterns: Elements of Reusable Object-Oriented Software" (Padrões de Projeto: Elementos de Software Orientado a Objetos Reutilizáveis).
O padrão Decorator é um padrão de projeto de software que permite adicionar dinamicamente responsabilidades adicionais a um objeto individual, sem afetar o comportamento de outros objetos do mesmo tipo. Isso é conseguido ao criar objetos decoradores que envolvem o objeto original e fornecem a funcionalidade adicional. O padrão Decorator é usado para adicionar comportamentos ou atributos a um objeto sem precisar modificar sua classe ou criar subclasses.
O padrão Decorator pode ser usado em vários casos, incluindo:
- Adicionar responsabilidades dinamicamente a um objeto individual, sem afetar outros objetos do mesmo tipo.
- Permitir que as responsabilidades sejam adicionadas e removidas independentemente uns dos outros.
- Aplicar responsabilidades opcionais a objetos sem precisar modificar sua classe ou criar subclasses.
- Fornecer uma alternativa ao uso de herança multipla para estender a funcionalidade de um objeto.
Exemplos comuns de uso incluem a adição de funcionalidades adicionais a objetos como formulários, componentes de interface gráfica de usuário, objetos de arquivo, etc.
class BaseComponent {
operation() {
return "base component";
}
}
class Decorator {
constructor(component) {
this.component = component;
}
operation() {
return this.component.operation();
}
}
// Decoradores concretos
class DecoratorExampleA extends Decorator {
operation() {
return `DecoratorExampleA(${this.component.operation()})`;
}
}
class DecoratorExampleB extends Decorator {
operation() {
return `DecoratorExampleB(${this.component.operation()})`;
}
}
// Uso do decorador
const component = new BaseComponent();
console.log(component.operation()); // "base component"
const decoratorA = new DecoratorExampleA(component);
const decoratorB = new DecoratorExampleB(decoratorA);
console.log(decoratorB.operation()); // "ConcreteDecoratorB(ConcreteDecoratorA(Component))"
A classe BaseComponent é o componente base que define a operação básica. A classe Decorator é a classe base para todos os decoradores que é responsável por envolver o componente base e fornecer sua operação.
As classes DecoratorExampleA e DecoratorExampleB são as classes decoradoras que estendem a classe Decorator e fornecem funcionalidades adicionais para o componente base. Eles sobreescrevem a operação e adicionam sua própria funcionalidade à operação base.
O código define uma instância do componente base BaseComponent e, em seguida, cria duas instâncias decoradoras DecoratorExampleA e DecoratorExampleB, que envolvem o componente base e adicionam suas próprias funcionalidades à operação base.
Ao imprimir o resultado da operação do decorador B, vemos que as funcionalidades adicionais dos decoradores A e B são aplicadas à operação base do componente base.
Simples, né ?
O padrão Decorator pode ser útil em muitas situações onde é necessário adicionar dinamicamente responsabilidades adicionais a objetos. Algumas situações comuns onde o padrão Decorator é usado incluem:
- Adicionar funcionalidades adicionais a objetos sem mudar sua estrutura básica.
- Adicionar dinamicamente responsabilidades adicionais a objetos sem mudar sua classe.
- Aplicar comportamentos diferentes a objetos sem usar herança.
- Controlar a composição de objetos para aplicar comportamentos adicionais a eles.
- Implementar funcionalidades opcionais em objetos, sem precisar mudar seu código-fonte original.
O padrão Decorator é amplamente utilizado em bibliotecas e frameworks, como Angular, React, etc. É uma abordagem poderosa para adicionar responsabilidades dinamicamente a objetos, preservando a estrutura básica dos objetos e permitindo uma flexibilidade maior em seus comportamentos.
Conclusão
Em resumo, o padrão Decorator fornece uma forma flexível de adicionar comportamentos a objetos sem afetar sua estrutura subjacente. Ele é uma alternativa viável à herança para extender a funcionalidade de objetos em tempo de execução.
Espero ter ajudado, até a próxima.
Top comments (0)