1. O que é o Padrão Decorator
O padrão decorator é um padrão de design estrutural que permite adicionar recursos adicionais a um objeto dinamicamente sem modificar o código do objeto. Isso é alcançado envolvendo o objeto em uma classe decoradora, proporcionando a capacidade de adicionar, modificar ou aprimorar o comportamento do objeto em tempo de execução.
2. Características e Vantagens do Padrão Decorator
As características e vantagens do padrão decorator incluem:
- Extensão dinâmica da funcionalidade de um objeto sem modificar seu código.
- Conformidade com o Princípio Aberto-Fechado, permitindo a adição e remoção dinâmica de decoradores.
- Capacidade de combinar vários decoradores para alcançar extensões de funcionalidade aninhadas.
- Independência dos decoradores da forma como o objeto é decorado, permitindo que as alterações sejam feitas de forma independente.
3. Exemplos de Aplicações Práticas do Padrão Decorator
O padrão decorator possui diversas aplicações práticas no desenvolvimento de software, tais como:
- Adição dinâmica de funcionalidade de registro
- Adição dinâmica de funcionalidade de cache
- Validação dinâmica de dados
4. Implementação do Padrão Decorator em Golang
4.1. Diagrama de Classe UML
4.2. Introdução do Exemplo
No exemplo, temos uma interface Component e uma classe ConcreteComponent que implementa o método Operation da interface Component.
Depois temos uma classe Decorator, que também implementa a interface Component. A classe Decorator possui uma variável membro do tipo Component.
Ambas as classes ConcreteDecoratorA e ConcreteDecoratorB herdam da classe Decorator e implementam funcionalidades adicionais sobrescrevendo o método Operation.
4.3. Passo 1 da Implementação: Definir a interface e a classe de implementação
type Component interface {
Operation() string
}
type ConcreteComponent struct {}
func (c *ConcreteComponent) Operation() string {
return "operação específica do componente"
}
4.4. Passo 2 da Implementação: Definir o decorador
type Decorator struct {
component Component
}
func (d *Decorator) Operation() string {
return d.component.Operation()
}
4.5. Passo 3 da Implementação: Implementação do decorador
type ConcreteDecoratorA struct {
Decorator
addedState string
}
func (c *ConcreteDecoratorA) Operation() string {
c.addedState = "Novo Estado"
return c.addedState + " " + c.component.Operation()
}
type ConcreteDecoratorB struct {
Decorator
}
func (c *ConcreteDecoratorB) Operation() string {
return "operação específica do decorador B " + c.component.Operation()
}
4.6. Passo 4 da Implementação: Utilizando o decorador
func main() {
component := &ConcreteComponent{}
decoratorA := &ConcreteDecoratorA{}
decoratorA.component = component
decoratorB := &ConcreteDecoratorB{}
decoratorB.component = decoratorA
result := decoratorB.Operation()
fmt.Println(result)
}
5. Comparação do Padrão Decorator com Outros Padrões de Design
5.1. Comparação com Herança
Comparado com a herança, o padrão decorator pode adicionar funcionalidade dinamicamente sem modificar o código existente, enquanto a herança é estática e precisa ser determinada em tempo de compilação.
5.2. Comparação com o Padrão de Proxy Estático
O padrão decorator e o padrão de proxy estático podem ambos alcançar a extensão de funcionalidades, mas o padrão decorator é mais flexível e permite a adição e remoção dinâmica de funcionalidades.
5.3. Comparação com o Padrão de Proxy Dinâmico
Tanto o padrão decorator quanto o padrão de proxy dinâmico podem estender a funcionalidade de objetos em tempo de execução. No entanto, o padrão decorator decora um único objeto, enquanto o padrão de proxy dinâmico envolve acesso indireto entre o objeto proxy e o objeto de destino.