Guia de Referência: Princípios SOLID no Desenvolvimento de Software
Este documento serve como base de conhecimento sobre os princípios SOLID, um acrônimo para cinco regras de design de software orientado a objetos, introduzidas por Robert C. Martin (Uncle Bob). O objetivo do SOLID é criar códigos mais legíveis, testáveis, flexíveis e fáceis de manter.
1. S - Single Responsibility Principle (SRP)
Princípio da Responsabilidade Única
Conceito: Uma classe, módulo ou função deve ter um, e apenas um, motivo para mudar. Ela deve possuir apenas uma responsabilidade ou cobrir apenas uma funcionalidade de negócio.
- Problema comum: God Classes (classes que fazem tudo, ex: gerenciam dados, autenticam usuários e enviam e-mails).
- Solução: Quebrar a classe multifuncional em classes menores, focadas em tarefas únicas.
- Exemplo Prático: * Incorreto: Uma classe
Pedidoque calcula o total, salva no banco de dados e envia um e-mail de confirmação.- Correto: A classe
Pedidogerencia os itens, uma classePedidoRepositorysalva no banco e uma classeEmailServiceenvia a notificação.
- Correto: A classe
2. O - Open/Closed Principle (OCP)
Princípio Aberto/Fechado
Conceito: Entidades de software (classes, módulos, funções) devem estar abertas para extensão, mas fechadas para modificação. Você deve conseguir adicionar novos comportamentos sem alterar o código original.
- Problema comum: Uso excessivo de blocos
if/elseouswitch/caseque crescem toda vez que uma nova regra de negócio ou tipo é adicionado. - Solução: Utilizar abstrações (interfaces ou classes abstratas) e polimorfismo.
- Exemplo Prático:
- Incorreto: Uma classe
CalculadoraDeDescontocom umswitchpara verificar se o cliente é "VIP", "Regular" ou "Estudante". - Correto: Uma interface
Descontocom o métodocalcular(). Cada tipo de cliente implementa essa interface (DescontoVIP,DescontoEstudante). Para criar um novo desconto, basta criar uma nova classe sem alterar a calculadora.
- Incorreto: Uma classe
3. L - Liskov Substitution Principle (LSP)
Princípio da Substituição de Liskov
Conceito: Classes derivadas (subclasses) devem ser capazes de substituir suas classes base (superclasses) sem que isso altere a correção ou o comportamento esperado do programa.
- Problema comum: Herança incorreta ou forçada, onde a classe filha joga uma exceção (
NotImplementedException) ou altera radicalmente a lógica de um método herdado. - Solução: Se a subclasse não consegue realizar todas as ações da classe pai, repense a hierarquia. Use composição em vez de herança ou segregue os comportamentos.
- Exemplo Prático:
- Incorreto: Uma classe pai
Passarocom o métodovoar(). A classe filhaPinguimherda dePassaro, mas lança um erro emvoar(), pois pinguins não voam. - Correto: Criar uma interface
PassaroQueVoaou separar as especializações de forma quePinguimnão herde comportamentos que não possui.
- Incorreto: Uma classe pai
4. I - Interface Segregation Principle (ISP)
Princípio da Segregação de Interfaces
Conceito: Uma classe não deve ser forçada a depender de interfaces ou métodos que ela não utiliza. É melhor ter várias interfaces específicas do que uma única interface genérica ("gorda").
- Problema comum: Interfaces gigantescas que forçam classes clientes a implementar métodos vazios apenas para satisfazer o contrato.
- Solução: Dividir a interface grande em interfaces menores e altamente coesas.
- Exemplo Prático:
- Incorreto: Uma interface
DispositivoMultifuncionalcom os métodosimprimir(),escanear()eenviarFax(). Uma impressora simples que herda dessa interface terá que deixar o métodoenviarFax()em branco. - Correto: Separar em três interfaces independentes:
Impressora,ScannereFax. As classes implementam apenas as interfaces correspondentes às suas capacidades reais.
- Incorreto: Uma interface
5. D - Dependency Inversion Principle (DIP)
Princípio da Inversão de Dependência
Conceito: Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações. Além disso, abstrações não devem depender de detalhes; detalhes devem depender de abstrações.
- Problema comum: Alto acoplamento. Código de regra de negócio instanciando diretamente classes de infraestrutura (como conexões de banco de dados ou bibliotecas de terceiros).
- Solução: Injetar dependências por meio de interfaces, invertendo o controle do fluxo.
- Exemplo Prático:
- Incorreto: Uma classe de negócio
GerenciadorDeUsuariocria manualmente uma instância deMySQLConnectiondentro do seu construtor. (Se o banco mudar para MongoDB, o gerenciador quebra). - Correto:
GerenciadorDeUsuariorecebe em seu construtor uma interfaceDatabaseConnection. Não importa qual banco está sendo usado por trás, desde que ele respeite a interface contratada.
- Incorreto: Uma classe de negócio
Resumo dos Benefícios do SOLID
- Manutenibilidade: Alterações em uma parte do sistema não causam efeitos cascata inesperados.
- Testabilidade: Facilidade extrema para criar Mocks e realizar testes de unidade robustos devido ao baixo acoplamento.
- Extensibilidade: O sistema cresce de forma orgânica e modular, aceitando novas features com menor custo de desenvolvimento.
- Reuso de Código: Componentes altamente coesos e desacoplados podem ser reaproveitados em múltiplos pontos do sistema.