Você já ouviu falar desses padrões de projeto? Sabe a diferença entre eles? A verdade é que esses dois padrões de projeto possuem usos bem distintos, mas sua implementação é relativamente semelhante, uma vez que ambos utilizam como base a **composição de classes**. Assim, muitas vezes ficamos com uma pulga atrás da orelha sobre como e quando aplicar cada um desses padrões.
Hoje, eu vou tentar **descomplicar a aplicabilidade** e **conceito** desses dois padrões estruturais, trazidos pela **GoF** (Gang of Four) em seu livro "**Padrões de Projeto**".
[TOC]
## 1. Padrões de Projeto Estruturais
De acordo com a **GoF**: "*Os padrões estruturais se preocupam com a forma como classes e objetos são compostos para formar estruturas maiores*".
Em suma, diferente dos **padrões criacionais** que abstraem processos de instanciação, e dos **padrões comportamentais** que se preocupam mais com o algorítmo e a atribuição de responsabilidades entre objetos, os **padrões estruturais** se preocupam com a "forma" das classes, reaproveitando a herança de objetos simples para composição de estruturas mais complexas.
## 2. O Composite
### 2.1. Conceito
O Composite é o **quarto padrão** desta categoria apresentado pela GoF, e o primeiro que eu pretendo trazer neste artigo. Como os próprios autores colocam, a intenção oficial deste padrão seria "*compor objetos em estruturas de árvore para representarem hierarquias partes-todo. Composite permite aos clientes tratarem de maneira uniforme objetos individuais e composições de objetos*".
Ficou confuso? Não se preocupe que a ideia aqui é justamente destrinchar essa intenção e entender na prática o que isso significa.

*Diagrama oficial do livro "Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos"*
A ideia por trás deste padrão, nada mais é do que a invocação encadeada de um método, delegada pela classe **Composite**, assim chamando a **implementação de seus filhos**.
### 2.2. Exemplo prático
Vejamos o seguinte cenário:
Em um supermercado, você possui duas formas de comprar um refrigerante; você pode comprar a **unidade**, ou comprar um **fardo com 12 unidades**. Aqui, nós temos um **Composite**: a noção de que o **fardo** (*estrutura*) se comporta como um produto, e que ele pode dizer seu preço delegando o seu valor, somando assim os custos das unidades filhas e utilizando como seu próprio.
Claro, o cenário acima só faz sentido se o fardo não possuir um valor fixo, e sim que seu valor se resume no total de unidades que há dentro do mesmo.
Vejamos um código do cenário descrito (no caso, utilizando Java para exemplificar):
```Java=
public interface Produto {
public Double getValor();
}
```
No exemplo acima, definimos uma interface **Produto**, que será implementada tanto pela unidade de "refrigerante", quanto pelo fardo. O método em comum que será implementado por eles, no nosso caso, é o `getValor()`.
---
```Java=
public class Refrigerante implements Produto {
private String nome;
private Double valor;
public Refrigerante(String nome, Double valor) {
this.nome = nome;
this.valor = valor;
}
public String getNome() {
return nome;
}
@Override
public Double getValor() {
return valor;
}
}
```
O refrigerante, por sua vez, possui o valor e um nome. A implementação do `getValor()`, por ser uma única unidade, apenas retorna o seu próprio valor.
```Java=
public class FardoDeRefrigerante implements Produto {
private List<Produto> produtos = new ArrayList<>();
public void add(Produto ...produtos) {
this.produtos.addAll(Arrays.asList(produtos));
}
public void add(Produto produto, int quantidade) {
for (int i = 0; i < quantidade; i++) {
this.produtos.add(produto);
}
}
public void remove(Produto produto) {
produtos.remove(produto);
}
@Override
public Double getValor() {
Double soma = 0d;
for (Produto produto : produtos) {
soma += produto.getValor();
}
return soma;
}
}
```
Acima temos o fardo de refrigerantes, atuando como **Composite**, seu "valor" é delegado para as unidades que há dentro do mesmo. Ou seja, se houver 5 unidades de refrigerante, cada um com um valor "5", o valor do fardo será de 25.
```Java=
Produto soda = new Refrigerante("Soda", 3.5);
FardoDeRefrigerante fardoDeRefrigerante = new FardoDeRefrigerante();
fardoDeRefrigerante.add(soda, 6);
```
```Java=
Produto soda1 = new Refrigerante("Soda", 2.75);
Produto soda2 = new Refrigerante("Soda", 3.99);
...
FardoDeRefrigerante fardoDeRefrigerante = new FardoDeRefrigerante();
fardoDeRefrigerante.add(soda1, soda2, ...);
```
O interessante neste padrão de projetos, é que a complexidade desse tipo de estrutura não acaba por aí. Como a classe `FardoDeRefrigerante` possui uma lista dentro de si do tipo `Produto`, ela é capaz de suportar até mesmo outros fardos dentro de si mesma. Apesar de o "fardo de refrigerante" não ser o melhor exemplo nesse caso, podemos imaginar uma caixa dentro de outra caixa, e cada uma delas com produtos de diferentes valores dentro de sí, as caixas internas totalizariam o valor dos produtos internos, e a caixa externa totalizaria o valor das caixas internas, parecendo muito com a estrutura abaixo:

*Exemplo de como a estrutura de um composite pode ficar. Fonte: "Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos"*
## 3. O Decorator
### 3.1. Conceito
O **Decorator**, também comumente chamado de "*Wrapper*", é o **quinto padrão** de projeto estrutural listado pela GoF.
Sua intenção é relativamente simples de se entender, uma vez que ela apenas busca acrescentar alguma funcionalidade dentro de classes. Conforme descrito pelos autores: "*[Sua intenção é] dinamicamente, agregar responsabilidades adicionais a um objeto. Os Decorators fornecem uma alternativa flexível ao uso de subclasses para extensão de funcionalidades*".

*Diagrama oficial do livro “Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos”*
A semelhança entre o **diagrama do Decorator** e **Composite** não é atoa: como dito no início do artigo, ambos utilizam **composição de classes**. Este é um dos motivos por às vezes haver confusão entre esses dois padrões de projeto.
### 3.2. Exemplo prático
Vejamos o seguinte cenário:
Em uma determinada lanchonete, cada um dos lanches disponíveis no cadápio possui sua versão normal, gourmet e vegano. Trazendo para o mundo do desenvolvimento, de qual forma poderíamos reaproveitar o máximo de métodos/atributos em comum entre cada um dos lanches (objetos)? Aqui, podemos aplicar o decorator, onde o **lanche gourmet** e **vegano** são "variantes" de um **lanche comum**.
Segue exemplo abaixo, utilizando um X-Salada e um Cachorro-quente como opções de cardápio:
```Java=
public interface Lanche {
public Double getValor();
}
```
Podemos começar com uma declaração simples do que poderia ser o lanche. Para simplificar o Decorator, vamos apenas alterar o preço entre gourmet, vegano e comum. Assim, vamos ficar apenas com o método `getValor()`.
---
```Java=
public class XSalada implements Lanche {
private Double valor;
// ...código omitido
public XSalada(Double valor) {
this.valor = valor;
}
@Override
public Double getValor() {
return valor;
}
// ...código omitido
}
```
```Java=
public class CachorroQuente implements Lanche {
private Double valor;
// ...código omitido
public CachorroQuente(Double valor) {
this.valor = valor;
}
@Override
public Double getValor() {
return valor;
}
// ...código omitido
}
```
Aqui, temos a implementação dos nossos lanches "comuns". Estes objetos também são chamados de "componentes concretos", dentro deste padrão de projeto.
Cada um dos componentes concretos possui seus próprios atributos e métodos. Para simplificar, vamos focar apenas no valor dos lanches.
---
```Java=
public abstract class LancheDecorator implements Lanche {
protected Lanche lanche;
protected LancheDecorator(Lanche lanche) {
this.lanche = lanche;
}
}
```
Então, a primeira implementação do nosso **Decorator** aparece. Neste primeiro momento, ele serve apenas como uma classe intermediária para os **decoradores concretos**, que virão a seguir. Em alguns cenários (inclusive o nosso), a criação deste método torna-se opcional, uma vez que ele apenas define a forma de instanciação dos decoradores filhos. Ainda assim, neste exemplo nós seguiremos a estrutura proposta pela GoF.
Em um cenário mais real, esta classe poderia possuir alguns métodos e obrigar a sua implementação para as classes filhas. No nosso caso, estamos apenas delegando a implementação de `getValor()`, que vem da interface `Lanche`.
---
Como **decoradores concretos**, conforme nosso exemplo, teríamos os seguintes:
```Java=
public class LancheVegano extends LancheDecorator {
public LancheVegano(Lanche lanche) {
super(lanche);
}
@Override
public Double getValor() {
return this.lanche.getValor() + 7.5;
}
}
```
```Java=
public class LancheGourmet extends LancheDecorator {
public LancheGourmet(Lanche lanche) {
super(lanche);
}
@Override
public Double getValor() {
return this.lanche.getValor() + 9.95;
}
}
```
Como pode ser observado, os **Decorators**, especificamente no nosso caso, possuem apenas uma modificação de incremento de valor. Esse "comportamento extra" trazido aos lanches, servirá como modelo para decorar componentes concretos, como por exemplo o `XSalada` ou o `CachorroQuente`. Quando um `LancheGourmet` for instanciado com um `XSalada` como parâmetro portanto, um valor de "9,95" será acrescentado ao valor original do x-salada, e quando um `LancheVegano` for instanciado com um `CachorroQuente` como parâmetro portanto, um valor de "7,5" será acrescentado ao valor original do cachorro-quente.
Obviamente, o incremento de valor é apenas um exemplo. Utilizando deste conceito, qualquer adição de funcionalidade ou alteração de comportamento poderia ser aplicado nos lanches. O importante é compreender o objetivo: ao invés de criarmos as classes `CachorroQuente`, `CachorroQuenteVegano`, `CachorroQuenteGourmet`, `XSalada`, `XSaladaVegano`, `XSaladaGourmet` etc., basta decorarmos os componentes concretos (`XSalada` e `CachorroQuente`) com nossos decoradores concretos.
```Java=
Lanche xSalada = new XSalada(12d); // Valor de 12,00
Lanche xSaladaGoumert = new LancheGourmet(xSalada); // Valor de 21,95
Lanche xSaladaVegano = new LancheVegano(xSalada); // Valor de 19,50
```
## 4. Opinião do Autor
Acredito que esses dois padrões de projetos são muito interessantes, e de certa forma é bem comum de vê-los em sistemas. O padrão de projeto **Composite** é normalmente utilizado, por exemplo, para rodar uma bateria de validações em cima de um objeto. Enquanto o **Decorator** serve para extender funcionalidades dentro de uma classe já existente, sem alterar a classe original e preservando os princípios **SOLID**.
De qualquer forma, espero ter conseguido elucidar os seus usos e descomplicado os seus conceitos. Claro que a forma de implementação pode variar bastante dependendo de como que você utiliza, mas o importante é conhecer o padrão e saber quando encaixá-lo no seu sistema. Não siga à risca os diagramas propostos pela GoF, ou os exemplos citados; adeque-os de acordo com suas necessidades e situações.