Backend
Padrão de Projeto Decorator: Adicionando Funcionalidades sem Quebrar sua Arquitetura
Gabriel Bertonsin DEV Community
24 views
Se você já trabalhou com orientação a objetos por algum tempo, provavelmente já se deparou com este dilema: como adicionar novas funcionalidades a um objeto sem criar uma explosão de subclasses? Imagine um sistema de componentes gráficos onde você precisa combinar bordas, sombras, cores e efeitos de diferentes formas. Criar uma subclasse para cada combinação possível rapidamente se torna insustentável.
É exatamente para resolver esse tipo de problema que existe o Decorator, um dos padrões de projeto estruturais mais elegantes do catálogo GoF (Gang of Four).
Neste artigo, vou explicar o que é o padrão Decorator, quando ele deve ser usado e como implementá-lo na prática com um exemplo completo em Java.
O que é o padrão Decorator?
O Decorator é um padrão de design estrutural que permite adicionar comportamento a objetos individuais de forma dinâmica e transparente, sem afetar outros objetos da mesma classe.
Em vez de estender uma classe para adicionar uma nova responsabilidade (o que gera herança rígida e múltiplas subclasses), o Decorator envolve o objeto original com uma camada adicional de comportamento — como se fosse uma "embalagem" que soma funcionalidades sem alterar a estrutura interna do objeto decorado.
O resultado é um sistema muito mais flexível e modular, no qual novas combinações de comportamento podem ser criadas em tempo de execução, simplesmente combinando decoradores diferentes.
Vantagens do Decorator
Flexibilidade e modularidade: permite estender o comportamento de objetos individuais sem afetar os demais.
Evita a explosão de subclasses: ao invés de criar uma classe para cada combinação de funcionalidades, você combina decoradores.
Responsabilidade única: cada decorador cuida de uma única responsabilidade, mantendo o código mais limpo e coeso.
Quando usar o Decorator?
Esse padrão é especialmente útil quando:
Você precisa adicionar responsabilidades a objetos dinamicamente, sem modificar seu código-fonte.
Você quer evitar a criação de subclasses excessivas para representar cada combinação possível de comportamentos.
Você busca uma alternativa à herança para estender funcionalidades de forma mais flexível.
Estrutura do Padrão
O Decorator é composto por quatro elementos principais:
1. Componente (Component)
Define a interface comum para os objetos que podem receber responsabilidades adicionais. É o contrato que tanto os componentes concretos quanto os decoradores devem seguir.
// Componente
interface Component {
void draw();
}
2. Componente Concreto (Concrete Component)
Implementa o comportamento básico do componente — é o objeto "puro", sem nenhuma decoração aplicada ainda.
// Componente Concreto
class Button implements Component {
public void draw() {
System.out.println("Drawing a button");
}
}
3. Decorador (Decorator)
Essa é a peça central do padrão. O decorador:
Mantém uma referência para um objeto do tipo Component.
Implementa a mesma interface do componente base, garantindo que possa ser usado no lugar dele.
Encapsula o componente original e adiciona um comportamento extra.
Pode ser estendido por subclasses para implementar responsabilidades específicas.
// Decorador
abstract class BorderDecorator implements Component {
protected Component component;
public BorderDecorator(Component component) {
this.component = component;
}
public void draw() {
component.draw();
drawBorder();
}
protected abstract void drawBorder();
}
Note que o método draw() primeiro chama o comportamento original (component.draw()) e depois adiciona o novo comportamento (drawBorder()). Essa é a essência do padrão: compor comportamentos em camadas.
4. Decorador Concreto (Concrete Decorator)
Estende o decorador abstrato e implementa a funcionalidade específica que será adicionada.
// Decorador Concreto
class RedBorderDecorator extends BorderDecorator {
public RedBorderDecorator(Component component) {
super(component);
}
protected void drawBorder() {
System.out.println("Drawing a red border");
}
}
Colocando tudo em prática
Com as classes definidas, podemos ver o padrão em ação:
public class Main {
public static void main(String[] args) {
// Componente original
Component button = new Button();
// Decorando o componente original com uma borda vermelha
Component decoratedButton = new RedBorderDecorator(button);
// Desenhando o componente decorado
decoratedButton.draw();
}
}
Saída esperada:
Drawing a button
Drawing a red border
Perceba que o botão original não foi alterado. Ele continua existindo como uma implementação independente. A borda vermelha foi adicionada dinamicamente, "envolvendo" o botão em uma nova camada de comportamento. Se amanhã precisarmos de um botão com borda azul, ou com borda e sombra combinadas, basta criar (ou combinar) novos decoradores — sem tocar na classe Button.
Por que isso importa?
O grande ganho do Decorator está em respeitar o princípio Aberto/Fechado (Open/Closed Principle): as classes ficam abertas para extensão, mas fechadas para modificação. Isso significa que podemos adicionar novos comportamentos ao sistema sem correr o risco de quebrar código já existente e testado.
Além disso, como os decoradores podem ser empilhados (um decorador pode envolver outro decorador), é possível construir combinações complexas de comportamento a partir de peças simples e reutilizáveis — algo muito mais elegante do que uma árvore de herança cheia de subclasses.
Conclusão
O padrão Decorator é uma ferramenta poderosa para quem busca flexibilidade no design de sistemas orientados a objetos. Ao substituir a herança rígida por composição dinâmica, ele permite adicionar responsabilidades a objetos de forma modular, reutilizável e sem efeitos colaterais sobre outras instâncias da mesma classe.
Esse padrão é amplamente utilizado em bibliotecas e frameworks conhecidos — por exemplo, o próprio java.io do Java (como BufferedReader envolvendo um FileReader) é um exemplo clássico de Decorator aplicado na prática.
Entender e saber aplicar o Decorator é um passo importante para escrever código mais limpo, extensível e alinhado com boas práticas de design orientado a objetos.
Read original: https://dev.to/gabriel_berton_brito/padrao-de-projeto-decorator-adicionando-funcionalidades-sem-quebrar-sua-arquitetura-c0h
← Previous
XML Configuration Mode: Decoupling Your API Catalog from Business Code
Next →
Milestone Reached: YINI Syntax Highlighting Is Now on the VS Code Marketplace
Related
The benchmark everyone cited for "fastest backend" was archived in March, and the reason is the interesting part
Backend
56
Dev.to (EN Zone)
Finding Exoplanets in Noisy Data with Machine Learning
Backend
46
DEV Community
How to automatically find the batch size when using Accelerate with FSDP2? [D]
Backend
43
Reddit r/MachineLearning
Cross-Chain Bridge Risk Assessment: Aave V3
Backend
36
DEV Community
Comments0
No comments yet — be the first