Pular para o conteúdo

Atividade 09: Composite

Para cada cenário abaixo, indique se o padrão Composite é apropriado ou não e justifique em 2–3 frases.

  1. Um explorador de arquivos que precisa listar e calcular o tamanho de pastas, que podem conter arquivos ou outras pastas (estrutura recursiva).
  2. 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.
  3. 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.
  4. Um cadastro de produtos com uma lista simples e plana (nome, preço, estoque) que nunca terá itens compostos ou hierarquia.
  5. 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.).

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.

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:

  1. 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?
  2. O que acontece ao adicionar um novo tipo (ex.: um ProdutoComDesconto ou um serviço de montagem)? Que bugs ou confusões esse código tende a gerar?
  3. 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?

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.

Implemente, em Java, um sistema que trate pratos e combos de forma uniforme, usando o padrão Composite.

  1. Crie a interface ItemMenu (o Component):
    • Métodos: String getNome() e double getPreco().
  2. Crie a folha Prato:
    • Campos nome e preco (recebidos no construtor).
    • getPreco() retorna o preço do prato.
  3. Crie o composto Combo:
    • Campo nome e uma lista de ItemMenu (filhos).
    • Métodos adicionar(ItemMenu item) e remover(ItemMenu item).
    • getPreco() deve somar recursivamente o preço dos filhos.
    • getNome() devolve o nome do combo.
  4. Crie uma classe de teste, por exemplo Main, que:
    • Monte pratos (ex.: Hamburguer, BatataFrita, Refrigerante) com preços.
    • Monte um Combo Duplo contendo dois hambúrgueres e um refrigerante.
    • Monte um Combo Família contendo o Combo Duplo dentro 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 interface ItemMenu.
    • 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.: BebidaAlcoolica com imposto especial) exigiria apenas uma nova folha, sem alterar o Combo nem a Main.