Technology Sep 12, 2026 · 5 min read

Padrão de Projeto Decorator: Adicionando Funcionalidades sem Quebrar sua Arquitetura

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...

DE
DEV Community
by Gabriel Bertonsin
Padrão de Projeto Decorator: Adicionando Funcionalidades sem Quebrar sua Arquitetura

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.

DE
Source

This article was originally published by DEV Community and written by Gabriel Bertonsin.

Read original article on DEV Community
Back to Discover

Reading List