O Dependency Inversion Principle (Princípio da Inversão de Dependência) é o "D" do SOLID e afirma que:
"Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações."
"Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações."
- ✅ Desacoplamento: Reduz a dependência entre módulos
- ✅ Flexibilidade: Facilita a troca de implementações
- ✅ Testabilidade: Permite usar mocks e stubs em testes
- ✅ Manutenibilidade: Mudanças em detalhes não afetam módulos de alto nível
Você tem um Sistema de Notificações que viola o DIP. Seu objetivo é refatorá-lo para seguir o princípio corretamente.
A classe NotificationService (alto nível) depende diretamente das classes concretas:
EmailService(baixo nível)SMSService(baixo nível)PushNotificationService(baixo nível)
Consequências:
- Difícil adicionar novos tipos de notificação
- Difícil testar sem enviar notificações reais
- Alto acoplamento entre as classes
- Violação do Open/Closed Principle também
- Criar uma abstração (interface)
INotificationSender - Fazer as classes de baixo nível implementarem a interface:
EmailService implements INotificationSenderSMSService implements INotificationSenderPushNotificationService implements INotificationSender
- Fazer a classe de alto nível depender da abstração:
NotificationServicedeve receberINotificationSender(não classes concretas)
# Execute a versão errada para ver como funciona
./gradlew runNa pasta Solution, crie as seguintes classes:
- INotificationSender.java - Interface que define o contrato de envio
- EmailService.java - Implementação que envia por email
- SMSService.java - Implementação que envia por SMS
- PushNotificationService.java - Implementação que envia push notifications
- NotificationService.java - Classe de alto nível que depende da interface (não das implementações!)
- SolutionVersion.java - Classe para demonstrar o uso da solução
Lembre-se: A classe NotificationService deve receber a dependência via construtor (Dependency Injection)!
- Abra o arquivo
App.java - Comente a linha que chama
WrongVersion.run() - Descomente a linha que chama
SolutionVersion.run() - Execute novamente:
./gradlew run
- Inversão de Dependência (DIP): Princípio de design que diz para depender de abstrações
- Injeção de Dependência (DI): Padrão/técnica para implementar o DIP (passar dependências via construtor, setter, etc.)
- Alto Nível: Contém lógica de negócio, regras, políticas (ex: NotificationService)
- Baixo Nível: Implementa detalhes técnicos, I/O, infraestrutura (ex: EmailService, SMSService)
Após implementar corretamente, você terá:
- ✅ Fácil extensão: Adicionar WhatsAppService sem modificar NotificationService
- ✅ Testável: Pode criar um MockNotificationSender para testes
- ✅ Desacoplado: NotificationService não conhece detalhes de implementação
- ✅ Flexível: Pode trocar implementações em tempo de execução
- A interface deve estar no mesmo nível conceitual da classe de alto nível
- Use injeção de dependência via construtor para passar a implementação
- Pense em como facilitar testes ao resolver o problema
- A classe de alto nível não deve criar instâncias das classes de baixo nível
Boa sorte! 🚀