image

Access unlimited bootcamps and 650+ courses

50
%OFF
Vinícius Cavalheiro
Vinícius Cavalheiro31/01/2025 01:23
Share

Day #01 - Os Princípios SOLID: A Base para um Código Sustentável e Manutenável

  • #Arquitetura de Sistemas
  • #Arquitetura

Os Princípios SOLID: A Base para um Código Sustentável e Manutenável

Antes de começar quero dizer que estou estudando para ser um programador cada vez melhor, todos os didas o que estudar e revisar, estarei aqui documentando para vocês também acompanharem e crescerem juntos. Bora lá? Quem quiser acompanhar e estudar comigo, deixa um comentário.

O desenvolvimento de software exige boas práticas para garantir um código limpo, flexível e de fácil manutenção. Nesse contexto, os princípios SOLID são fundamentais para a criação de sistemas robustos e escaláveis. SOLID é um acrônimo que representa cinco princípios essenciais da programação orientada a objetos, definidos por Robert C. Martin (Uncle Bob).

1. Single Responsibility Principle (SRP) - Princípio da Responsabilidade Única

Cada classe deve ter apenas um motivo para mudar. Isso significa que uma classe deve ter uma única responsabilidade bem definida.

Exemplo:

Errado:

public class RelatorioService {
  public void gerarRelatorio() { /* Gera o relatório */ }
  public void salvarNoBanco() { /* Salva no banco de dados */ }
}

Correto:

public class RelatorioGerador {
  public void gerarRelatorio() { /* Gera o relatório */ }
}

public class RelatorioRepositorio {
  public void salvarNoBanco() { /* Salva no banco de dados */ }
}

Ao separar as responsabilidades, evitamos acoplamento excessivo e tornamos o código mais modular.

2. Open/Closed Principle (OCP) - Princípio Aberto/Fechado

Os módulos de software devem estar abertos para extensão, mas fechados para modificação. Isso significa que devemos projetar classes que possam ser estendidas sem alterar seu código original.

Exemplo:

Errado:

public class CalculadoraDesconto {
  public double calcularDesconto(String tipo, double valor) {
      if ("BLACK_FRIDAY".equals(tipo)) {
          return valor * 0.5;
      } else if ("NATAL".equals(tipo)) {
          return valor * 0.3;
      }
      return valor;
  }
}

Correto:

public interface Desconto {
  double aplicar(double valor);
}

public class BlackFridayDesconto implements Desconto {
  public double aplicar(double valor) { return valor * 0.5; }
}

public class NatalDesconto implements Desconto {
  public double aplicar(double valor) { return valor * 0.3; }
}

public class CalculadoraDesconto {
  public double calcular(Desconto desconto, double valor) {
      return desconto.aplicar(valor);
  }
}

Dessa forma, ao adicionar novos tipos de descontos, não precisamos modificar a classe principal.

3. Liskov Substitution Principle (LSP) - Princípio da Substituição de Liskov

Uma classe derivada deve poder ser usada no lugar de sua classe base sem afetar a corretude do programa.

Exemplo:

Errado:

public class Ave {
  public void voar() { /* Implementação de voo */ }
}

public class Pinguim extends Ave {
  @Override
  public void voar() { throw new UnsupportedOperationException("Pinguins não voam"); }
}

O problema aqui é que a classe Pinguim quebra a expectativa da classe base. O correto seria criar uma hierarquia diferente:

Correto:

public class Ave {}

public class AveVoadora extends Ave {
  public void voar() { /* Implementação de voo */ }
}

public class Pinguim extends Ave { /* Sem sobrescrever voar */ }

Isso garante que todas as sub-classes respeitem o comportamento esperado.

4. Interface Segregation Principle (ISP) - Princípio da Segregação de Interfaces

Nenhuma classe deve ser forçada a implementar métodos que não utiliza. Interfaces grandes e genéricas devem ser divididas em múltiplas interfaces menores e mais específicas.

Exemplo:

Errado:

public interface Funcionario {
  void trabalhar();
  void gerenciar();
}

public class Desenvolvedor implements Funcionario {
  public void trabalhar() { /* Codando */ }
  public void gerenciar() { throw new UnsupportedOperationException("Desenvolvedores não gerenciam"); }
}

Correto:

public interface Trabalhavel {
  void trabalhar();
}

public interface Gerenciavel {
  void gerenciar();
}

public class Desenvolvedor implements Trabalhavel {
  public void trabalhar() { /* Codando */ }
}

public class Gerente implements Trabalhavel, Gerenciavel {
  public void trabalhar() { /* Trabalha */ }
  public void gerenciar() { /* Gerencia */ }
}

Isso evita a obrigação de implementar métodos desnecessários.

5. Dependency Inversion Principle (DIP) - Princípio da Inversão de Dependência

Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.

Exemplo:

Errado:

public class PedidoService {
  private MySQLRepositorio repositorio;
  public PedidoService() {
      this.repositorio = new MySQLRepositorio();
  }
}

Correto:

public interface Repositorio {
  void salvar(Pedido pedido);
}

public class MySQLRepositorio implements Repositorio {
  public void salvar(Pedido pedido) { /* Salva no MySQL */ }
}

public class PedidoService {
  private Repositorio repositorio;
  public PedidoService(Repositorio repositorio) {
      this.repositorio = repositorio;
  }
}

Agora podemos trocar o banco de dados sem alterar a lógica do PedidoService.

Conclusão

Os princípios SOLID ajudam a criar um código mais organizado, modular e de fácil manutenção. Aplicá-los corretamente reduz o acoplamento e melhora a extensibilidade do sistema. Ao desenvolver software, tenha sempre em mente esses princípios para garantir qualidade e sustentabilidade do seu código.

Share
Comments (0)