Lista de Exercícios 001 - SOLID
Exercício 1 – Single Responsibility Principle (SRP)
Seção intitulada “Exercício 1 – Single Responsibility Principle (SRP)”Você recebe uma classe RelatorioVendas:
public class RelatorioVendas {
private final List<Venda> vendas; private final LocalDate dataInicio; private final LocalDate dataFim;
public RelatorioVendas(List<Venda> vendas, LocalDate dataInicio, LocalDate dataFim) { this.vendas = vendas; this.dataInicio = dataInicio; this.dataFim = dataFim; }
public String gerarRelatorio() { StringBuilder sb = new StringBuilder(); sb.append("Relatório de Vendas\n"); sb.append("Período: ").append(dataInicio).append(" até ").append(dataFim).append("\n\n");
double total = 0.0; for (Venda venda : vendas) { sb.append("ID: ").append(venda.getId()) .append(" | Data: ").append(venda.getData()) .append(" | Cliente: ").append(venda.getCliente()) .append(" | Valor: R$ ").append(String.format("%.2f", venda.getValor())) .append("\n"); total += venda.getValor(); }
sb.append("\nTotal de vendas: R$ ").append(String.format("%.2f", total)).append("\n"); return sb.toString(); }
public void salvarRelatorio(String caminho) { String conteudo = gerarRelatorio(); try (FileWriter writer = new FileWriter(caminho)) { writer.write(conteudo); } catch (IOException e) { throw new RuntimeException("Erro ao salvar relatório em arquivo: " + caminho, e); } }
public void enviarRelatorioPorEmail(String email) { String conteudo = gerarRelatorio();
// Simulação de envio de email (sem integração real) System.out.println("Enviando relatório para " + email + "..."); System.out.println("Assunto: Relatório de Vendas"); System.out.println("Corpo da mensagem:\n" + conteudo); System.out.println("Relatório enviado com sucesso (simulado)."); }
// Classe auxiliar para simular uma venda real public static class Venda { private final String id; private final LocalDate data; private final String cliente; private final double valor;
public Venda(String id, LocalDate data, String cliente, double valor) { this.id = id; this.data = data; this.cliente = cliente; this.valor = valor; }
public String getId() { return id; }
public LocalDate getData() { return data; }
public String getCliente() { return cliente; }
public double getValor() { return valor; } }}- Explique por que essa classe viola o SRP.
- Liste pelo menos três responsabilidades diferentes que ela está assumindo.
- Proponha uma nova estrutura de classes que distribua essas responsabilidades de forma mais adequada.
Exercício 2 – Open/Closed Principle (OCP)
Seção intitulada “Exercício 2 – Open/Closed Principle (OCP)”Imagine um sistema de cálculo de frete onde existe uma classe CalculadoraFrete com um switch/if-else interno que decide o valor com base no tipo de entrega: Normal, Rápida, Expressa.
public class CalculadoraFrete {
public double calcularFrete(String tipoEntrega, double peso) { switch (tipoEntrega) { case "Normal": return peso * 5.0; case "Rápida": return peso * 10.0; case "Expressa": return peso * 20.0; default: throw new IllegalArgumentException("Tipo de entrega desconhecido: " + tipoEntrega); } }}A empresa deseja adicionar novos tipos de entrega (por exemplo, Entrega Noturna, Entrega Internacional) sem precisar modificar o código existente.
- Desenhe um diagrama de classes simples que respeite o OCP utilizando abstrações.
- No diagrama, deixe claro:
- Uso de interfaces ou classes abstratas
- Como cada tipo de entrega é representado
- Como a
CalculadoraFretepassa a depender da abstração, e não dos tipos concretos.
Exercício 3 – Liskov Substitution Principle (LSP)
Seção intitulada “Exercício 3 – Liskov Substitution Principle (LSP)”Considere uma hierarquia de classes onde Pato é a classe base e PatoDeBorracha é uma subclasse.
A classe Pato possui métodos como voar(), grasnar() e nadar().
Já PatoDeBorracha sobrescreve esses métodos para:
voar()lançar uma exceção ou não fazer nada (porque pato de borracha não voa);grasnar()emitir um som de apito engraçado em vez do grasnar esperado;nadar()ficar apenas boiando sem se mover.
- Explique, com suas palavras, quando uma subclasse viola o LSP.
- Argumente se
PatoDeBorrachaé ou não um bom subtipo dePatonesse contexto, considerando quem usa a classe base esperando “um pato de verdade”. - Descreva um cenário de uso em que o comportamento de
PatoDeBorrachapode surpreender quem espera umPatonormal (por exemplo, um simulador de voo de patos que, de repente, recebe umPatoDeBorrachae nada mais funciona como esperado), mostrando a quebra do LSP.
Exercício 4 – Interface Segregation Principle (ISP)
Seção intitulada “Exercício 4 – Interface Segregation Principle (ISP)”Suponha uma interface ITrabalhador com os métodos: trabalhar(), comer(), dormir(). Ela é implementada por Robo e Funcionario.
- Explique por que essa interface pode violar o ISP.
- Proponha um conjunto de interfaces menores que segregue melhor as responsabilidades.
- Escreva a nova definição dessas interfaces em pseudocódigo (ou sintaxe de alguma linguagem OO) e indique quais seriam implementadas por
Roboe porFuncionario.
Exercício 5 – Dependency Inversion Principle (DIP)
Seção intitulada “Exercício 5 – Dependency Inversion Principle (DIP)”Um módulo de alto nível ProcessadorDePagamento instancia diretamente uma classe concreta PagInseguro usando new, e chama seus métodos.
- Explique por que isso fere o DIP.
- Desenhe um diagrama simples mostrando a dependência atual (módulo de alto nível → classe concreta).
- Redesenhe o diagrama mostrando uma solução que siga o DIP, introduzindo:
- Uma abstração (interface) para o serviço de pagamento
- A inversão da dependência (módulo de alto nível depende da abstração).
- Descreva brevemente por quais maneiras o desenvolvedor poderia injetar a implementação concreta.