Atividade 10: Decorator
Exercício 1: Aplicações
Seção intitulada “Exercício 1: Aplicações”Para cada cenário abaixo, indique se o padrão Decorator é apropriado ou não e justifique em 2–3 frases.
- Um serviço de envio de e-mails que, em alguns fluxos, precisa registrar log, em outros comprimir os anexos e em outros fazer os dois, sem criar uma classe para cada combinação.
- Um editor de imagens que permite aplicar filtros em cadeia (brilho, contraste, sépia) em qualquer ordem e quantidade sobre uma foto.
- Um repositório de produtos usado pelo sistema todo; para um único caso de uso de alta leitura, é preciso adicionar cache em memória, sem mudar a interface que os demais consumidores já usam.
- Um catálogo de livros em que cada
Livrotem apenas título, autor e preço com estrutura simples e estável que nunca ganha variações de comportamento. - Uma concessionária em que todo carro vendido sai exatamente igual, sempre com o mesmo pacote opcional embutido na classe
Carro.
Para cada item, responda:
- “Faz sentido usar Decorator” ou “Não faz sentido usar Decorator”.
- Explique rapidamente o porquê (combinação dinâmica de responsabilidades, explosão de subclasses, interface estável, overengineering, etc.).
Exercício 2: Analogia
Seção intitulada “Exercício 2: Analogia”Crie uma analogia própria para explicar o padrão Decorator para alguém que não é da área de TI.
Na aula, usamos a pizza montada: a massa é a base, os ingredientes são adicionados por cima, e no fim continua sendo uma pizza, só que “decorada”. Agora crie uma outra analogia.
Descreva uma situação do mundo real em que:
- exista um objeto base que pode receber acréscimos opcionais, combináveis e empilháveis,
- cada acréscimo não muda o que o objeto é, apenas soma algo a ele (mantendo o “mesmo tipo” de coisa),
- e combinar acréscimos por duplicação antecipada (uma versão para cada combinação) seja inviável.
Exercício 3: Anti-pattern
Seção intitulada “Exercício 3: Anti-pattern”Considere o código Java abaixo, usado na tela de pedidos de uma cafeteria:
public class Cafe { boolean comLeite; boolean comChantilly; boolean comCanela;
public double custo() { double total = 5.0; if (comLeite) total += 1.5; if (comChantilly) total += 2.0; if (comCanela) total += 0.5; return total; }
public String getDescricao() { String descricao = "Café"; if (comLeite) descricao += " com leite"; if (comChantilly) descricao += " com chantilly"; if (comCanela) descricao += " com canela"; return descricao; }}Responda:
- Por que modelar os complementos como flags booleanas dentro de
Cafeé um problema de design? O que acontece com essa classe a cada novo complemento (ex.:café com caramelo)? - Que bugs e confusões esse código tende a gerar (ex.: esquecer de atualizar um dos métodos, combinações que fazem sentido juntas, comportamentos que não são só “somar preço”)?
- Proponha uma solução usando o padrão Decorator, explicando os papéis: a interface (
Bebida), o componente concreto (Cafe), o decorator abstrato e os decorators concretos (Leite,Chantilly). Como as combinações passam a ser montadas sem tocar na classeCafe?
Exercício 4: Implementação
Seção intitulada “Exercício 4: Implementação”Imagine que você foi contratado para criar o sistema de pedidos de uma cafeteria que acabou de abrir.
A casa serve uma bebida base (o café) e permite que o cliente combine complementos: leite, chantilly, calda de caramelo, entre outros. A equipe quer poder lançar novos complementos toda semana sem alterar a bebida base nem os complementos antigos.
Sua missão
Seção intitulada “Sua missão”Implemente, em Java, um sistema de bebidas que some complementos dinamicamente, usando o padrão Decorator.
- Crie a interface
Bebida(oComponent):- Métodos:
String getDescricao()edouble custo().
- Métodos:
- Crie o componente concreto
Cafe:getDescricao()retorna"Café".custo()retorna o preço base (ex.:5.0).
- Crie o decorator abstrato
Complemento:- Um campo
protected final Bebida bebida(recebido no construtor). - Implementa a interface
Bebida(pode deixar os métodos abstratos).
- Um campo
- Crie os decorators concretos:
Leite: soma" com leite"à descrição e1.5ao custo.Chantilly: soma" com chantilly"à descrição e2.0ao custo.- Cada um recebe uma
Bebidano construtor e delega ao objeto interno.
- Crie uma classe de teste, por exemplo
Main, que:- Monte e imprima as combinações: um
Cafepuro, umCafecomLeite, e umCafecomLeiteeChantilly(a ordem dos complementos deve ficar visível na descrição). - Mostre que todas as combinações usam a mesma interface
Bebidae que os custos somam camada por camada. - Explique, em um comentário ou README, como adicionar um novo complemento (ex.:
CaldaDeCaramelopor+3.0) exigiria apenas uma nova classeComplemento, sem alterarCafe,Leitenem aMain.
- Monte e imprima as combinações: um