Atividade 09: Composite
Exercício 1: Aplicações
Seção intitulada “Exercício 1: Aplicações”Para cada cenário abaixo, indique se o padrão Composite é apropriado ou não e justifique em 2–3 frases.
- Um explorador de arquivos que precisa listar e calcular o tamanho de pastas, que podem conter arquivos ou outras pastas (estrutura recursiva).
- Um cardápio digital de um restaurante em que seções podem conter itens de cardápio ou outras subseções, e o total de calorias de uma seção deve somar todos os itens abaixo dela.
- Um motor de interface gráfica em que um painel pode conter controles simples (botões, rótulos) ou outros painéis aninhados, e o sistema precisa desenhar/ocultar qualquer elemento da mesma forma.
- Um cadastro de produtos com uma lista simples e plana (nome, preço, estoque) que nunca terá itens compostos ou hierarquia.
- Um sistema de uma rede de lojas em que cada loja pertence a uma região, cada região a um estado e cada estado ao país, e é preciso, a partir de qualquer nível, somar o faturamento de tudo abaixo daquele nó.
Para cada item, responda:
- “Faz sentido usar Composite” ou “Não faz sentido usar Composite”.
- Explique rapidamente o porquê (estrutura recursiva parte-todo, tratamento uniforme, lista plana, overengineering, etc.).
Exercício 2: Analogia
Seção intitulada “Exercício 2: Analogia”Crie uma analogia própria para explicar o padrão Composite para alguém que não é da área de TI.
Na aula, usamos o organograma de uma empresa: um departamento contém funcionários ou sub-departamentos, e “quantas pessoas há abaixo de X” soma a árvore recursivamente. Agora crie uma outra analogia.
Descreva uma situação do mundo real em que:
- exista uma hierarquia recursiva (uma “coisa” que pode conter outras, inclusive do mesmo tipo),
- seja natural tratar o todo e as partes da mesma forma (ex.: perguntar algo para o nó raiz resolve a estrutura inteira),
- e esse tratamento uniforme simplifique quem usa a estrutura.
Exercício 3: Anti-pattern
Seção intitulada “Exercício 3: Anti-pattern”Considere o código Java abaixo, usado em um sistema de pedidos de uma loja:
public class Produto { String nome; double preco;}
public class Caixa { // pode conter produtos OU outras caixas String nome; List<Object> itens = new ArrayList<>();}
public class Pedido { public double calcularTotal(Object item) { if (item instanceof Caixa c) { double soma = 0; for (Object filho : c.itens) soma += calcularTotal(filho); // recursão "externa" return soma; } else if (item instanceof Produto p) { return p.preco; } return 0; }
public void imprimir(Object item) { // ... de novo, um if para Caixa e outro para Produto ... }}Responda:
- Por que calcular o total fora dos objetos, usando
instanceof, é um problema de design? Onde mora a lógica da árvore e o que acontece se outro trecho do sistema precisar percorrer a mesma estrutura? - O que acontece ao adicionar um novo tipo (ex.: um
ProdutoComDescontoou um serviço de montagem)? Que bugs ou confusões esse código tende a gerar? - Proponha uma solução usando o padrão Composite, explicando os papéis: a interface comum (
Component), a folha (Produto) e o composto (Caixa). Onde a recursão passa a morar e por que o cliente passa a chamar um único método sem distinguir os tipos?
Exercício 4: Implementação
Seção intitulada “Exercício 4: Implementação”Imagine que você foi contratado para criar o sistema de cardápio e comandas de um restaurante.
A casa vende pratos individuais e combos promocionais. Um combo pode conter pratos individuais e também outros combos (por exemplo, um “Combo Família” que inclui o “Combo Duplo” dentro dele). Sem o padrão, calcular o preço de um combo exigiria distinguir, item a item, se é um prato ou um sub-combo.
Sua missão
Seção intitulada “Sua missão”Implemente, em Java, um sistema que trate pratos e combos de forma uniforme, usando o padrão Composite.
- Crie a interface
ItemMenu(oComponent):- Métodos:
String getNome()edouble getPreco().
- Métodos:
- Crie a folha
Prato:- Campos
nomeepreco(recebidos no construtor). getPreco()retorna o preço do prato.
- Campos
- Crie o composto
Combo:- Campo
nomee uma lista deItemMenu(filhos). - Métodos
adicionar(ItemMenu item)eremover(ItemMenu item). getPreco()deve somar recursivamente o preço dos filhos.getNome()devolve o nome do combo.
- Campo
- Crie uma classe de teste, por exemplo
Main, que:- Monte pratos (ex.:
Hamburguer,BatataFrita,Refrigerante) com preços. - Monte um
Combo Duplocontendo dois hambúrgueres e um refrigerante. - Monte um
Combo Famíliacontendo oCombo Duplodentro dele, mais batatas e refrigerantes. - Imprima o preço de um prato isolado, do combo duplo e do combo família, sempre chamando o mesmo método
getPreco()sobre a interfaceItemMenu. - Mostre que o preço do combo família já inclui o preço do sub-combo (recursão).
- Explique, em um comentário ou README, como adicionar um novo tipo de item (ex.:
BebidaAlcoolicacom imposto especial) exigiria apenas uma nova folha, sem alterar oCombonem aMain.
- Monte pratos (ex.: