Princípios SOLID em Java: da teoria à prática
\n\nSOLID é um acrônimo de cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin (Tio Bob). Esses princípios ajudam a criar código flexível, sustentável e escalável. Neste artigo, analisaremos cada princípio com exemplos em Java, mostraremos como eles são violados e como aplicá-los corretamente.
\n\nPor que os princípios SOLID são necessários?
\nSem SOLID, o código rapidamente se transforma em "espaguete". Você já se deparou com uma situação em que alterar uma classe quebra outras três? Ou quando um método faz demais? SOLID resolve esses problemas. Cada princípio é uma regra que torna o código:
\n- \n
- Resistente a mudanças — novos requisitos não quebram a lógica antiga. \n
- Compreensível — cada classe é responsável por uma coisa. \n
- Testável — fácil de escrever testes unitários. \n
1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única
\nFormulação: "Uma classe deve ter apenas um motivo para mudar".
\nEm palavras simples: uma classe deve fazer apenas uma coisa. Se uma classe tem mais de uma responsabilidade, é difícil de manter.
\n\nViolação do SRP (código ruim)
\npublic class OrderService {\n public void createOrder(Order order) {\n // Lógica de criação do pedido\n saveToDatabase(order);\n sendEmailConfirmation(order);\n }\n\n private void saveToDatabase(Order order) {\n // Salvar no BD\n }\n\n private void sendEmailConfirmation(Order order) {\n // Enviar email\n }\n}\nProblema: a classe é responsável pela lógica de negócios, pelo trabalho com o BD e pelo envio de notificações. Alterar o serviço de email exigirá alteração no OrderService.
Implementação correta do SRP
\npublic class OrderService {\n private final OrderRepository repository;\n private final EmailService emailService;\n\n public OrderService(OrderRepository repo, EmailService email) {\n this.repository = repo;\n this.emailService = email;\n }\n\n public void createOrder(Order order) {\n repository.save(order);\n emailService.sendConfirmation(order);\n }\n}\n\npublic class OrderRepository {\n public void save(Order order) { /* lógica do BD */ }\n}\n\npublic class EmailService {\n public void sendConfirmation(Order order) { /* lógica de email */ }\n}\nAgora cada classe tem um motivo para mudar. OrderService muda apenas quando o processo de negócio de criação de pedidos é alterado.
2. Open/Closed Principle (OCP) — Princípio Aberto/Fechado
\nFormulação: "Classes devem estar abertas para extensão, mas fechadas para modificação".
\nIsso significa que você deve adicionar novas funcionalidades através de novo código, e não alterando o código existente.
\n\nViolação do OCP (código ruim)
\npublic class AreaCalculator {\n public double calculateArea(Object shape) {\n if (shape instanceof Rectangle) {\n Rectangle r = (Rectangle) shape;\n return r.width * r.height;\n } else if (shape instanceof Circle) {\n Circle c = (Circle) shape;\n return Math.PI * c.radius * c.radius;\n }\n throw new IllegalArgumentException("Forma desconhecida");\n }\n}\nPara adicionar um triângulo, é necessário alterar o método calculateArea — isso viola o OCP.
Implementação correta do OCP
\npublic interface Shape {\n double calculateArea();\n}\n\npublic class Rectangle implements Shape {\n private double width, height;\n public Rectangle(double w, double h) { this.width = w; this.height = h; }\n @Override\n public double calculateArea() { return width * height; }\n}\n\npublic class Circle implements Shape {\n private double radius;\n