devto 2026-09-13 원문 보기 ↗
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 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.
Esse padrão é especialmente útil quando:
O Decorator é composto por quatro elementos principais:
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();
}
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");
}
}
Essa é a peça central do padrão. O decorador:
Component.// 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.
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");
}
}
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.
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.
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.