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.