Os Princípios S.O.L.I.D. na P.O.O.
SOLID são princípios e/ou boas práticas da programação orientada a objetos, podendo serem aplicadas a qualquer linguagem de programação.
O que é SOLID? É um acrônimo criado por Michael Feathers, onde representam os cinco princípios da programação orientada a objetos e design de códigos, criados por Robert Cecil Martin por volta do ano 2000.
Quais são os cincos princípios?
1 - SRP - Single Responsibility Principle:
Princípio da responsabilidade única, onde uma classe deve ter um, e somente um motivo para mudar. Se uma classe precisa de mais de uma razão para mudar, ela está fazendo mais de uma coisa, quebrando o princípio;
- Exemplo quebrando o princípio (código ruim);
- Porque o código acima está quebrando o princípio do SRP? A classe Pessoa não deve saber como ela é persistida, além de que no meio do método, temos SQL para persistir os dados.
- Como podemos solucionar? Criar uma nova classe para persistir os dados, criando um padrão e isolando cada classe com sua função.
- Estrutura das Classes:
Note que a organização dos arquivos foi alterado, dividindo cada classe de acordo com as suas responsabilidades;
- Classe Pessoa:
- Classe PessoaRepository:
Caso seja necessário qualquer manutenção, alteração, o desenvolvedor vai apenas na classe necessária.
---
2 - OCP - Open | Closed Principle:
Princípio do aberto | fechado, onde deve ser capaz de estender um comportamento de uma classe sem a necessidade de modificá-lo, ou seja, não alterar uma classe que está em funcionamento.
Imagine que precisamos calcular o salário de um funcionário de acordo com o seu turno. Então foi criado uma classe enum para armazenar os tipos de períodos de trabalho, e uma classe para calcular a remuneração por período de trabalho.
- Classe enum TipoPeriodoTrabalho
- Classe RemuneracaoPorPeriodoDeTrabalho
Caso surgisse novas demandas a serem implementadas no turno, seria necessário alterar a classe RemuneracaoPorPeriodoDeTranalho acrescentando if com a lógica correspondente. Porém estaríamos quebrando o princípio;
Para não quebrar o princípio, pode - se criar uma classe para o salario base, e uma classe para cada período sendo extensível a classe salario base.
- Classe SalarioBase:
- Classes PeriodoManha, PeriodoTarde e PeriodoNoturno:
---
3 - LSP - Liskov Substitution Principle:
Princípio da substituição de Liskov, onde as classes derivadas devem ser substituíveis por suas classes bases.
A primeira vista, esse princípio parece ser o mais "complicado/difícil", porém o seu objetivo principal é ter certeza que novas classes derivadas (classe filha) estão estendendo das classes base (classe pai), mas sem alterar o seu comportamento (classe pai).
- Conceito de Herança (exemplo prático que pode ser encontrado em diversos artigos na web):
> Estende atributos e métodos de uma classe;
> Classe pai, é a classe que foi herdada;
> Classe filha, é a classe que herda da classe pai;
> Generalização - Similaridade entre classes e define novas classes, onde as classes "mais genéricas" são as classes pai;
> Especialização - Identifica atributos e métodos não correspondentes entre classes distintas, colocando - os na classe filha;
> Pessoa = Classe pai;
> PessoaFisica = Classe filha;
> PessoaJuridica = Classe filha;
A classe Pessoa é genérica e as classes PessoaFisica e PessoaJuridica são especializações;
Quando as classes filhas (PessoaFisica e PessoaJuridica) herdam da classe pai (Pessoa), elas passam a serem uma classe estendida, pois contém todos os (métodos e propriedades) da classe pai e suas próprias funcionalidades como (CPF ou CNPJ);
O princípio de LSP, entre outras palavras, nos ensina que um objeto de qualquer classe, deve permitir ser substituída em um sistema por qualquer instancia de suas classes filhas, já as derivadas, também devem possibilitar a substituição por sua classe pai. Este princípio está muito ligado ao uso do polimorfismo, pois assim qualquer método pode ser utilizado tanto na classe pai quanto nas classes filhas e utilizar todas as suas especializações sem nenhum problema.
Um detalhe importante, é que se temos uma classe filha que não utiliza todos os métodos da classe pai, podemos dizer que talvez estejamos fazendo um uso "não adequado" da herança na modelagem de classe.
Para resolver alguns/milhares de problemas, utilizamos Interface, onde as classes que a implementam vão responder como se fosse Interface.
---
4 - ISP - Interface Segregation Principle:
Princípio da segregação de interfaces, onde ter muitas interfaces especificas são melhores do que uma de forma única geral.
Se uma entidade não precisa de algum método que a interface obrigou a classe implementar, estamos quebrando este princípio, onde temos que ter interfaces especificas, e não generalistas!
- Exemplo de Interface Generalista:
Temos uma interface de cadastro (Icadastro):
Temos duas entidades (Cliente e Produto) que herdam a interface Icadastro;
Duas perguntas:
1) Faz algum sentido enviar e-mail para o cliente? R: SIM!
2) Faz algum sentido enviar e-mail para o produto? R: NÃO!
Sendo assim, conforme o princípio, criaremos interfaces especificas!
Agora, cada interface possui seus métodos específicos.
Agora cada entidade herda a interface especifica.
Sendo assim, podemos escrever métodos específicos de clientes e produtos com uma melhor segregação.
---
5 - DIP - Dependency Inversion Principle:
Princípio da inversão de dependência, onde devemos depender de abstrações e não das implementações.
a) Entidades devem depender de abstrações;
b) Entidades de alto nível não devem depender das de baixo nível;
c) Não devemos depender de detalhes e sim ABSTRAÇÕES;
Como devemos depender de abstrações e não de uma implementação, todos os princípios são aplicados, garantindo que o sistema seja mais desacoplado e coeso. Para isso, trabalhamos com a (injeção dependências), ou seja, injetar uma dependência é passar uma classe (interface) que será utilizada, para que a outra consuma seus recursos!
Importante:
Inversão de dependência NÃO é igual a injeção de dependência!
Inversão de dependência é um princípio (conceito) e a injeção de dependência é um padrão de projeto (design pattern).
- Exemplo:
Cada método não sabe o que o outro faz (utilizando o princípio da responsabilidade única);
Caso necessário alterar o tipo de banco de dados (sair: SQL, entrar: PostgreSQL), seria necessário alterar a classe de repositório sem alterar as outras, pois o código está desacoplado!
---
Não utilizar os conceitos S.O.L.I.D, a sua aplicação pode ter problemas como:
> Repetição de códigos (uma simples alteração deve ser replicada em vários pontos diferentes da aplicação);
> Código sem padrão/estrutura;
> Dificuldades para a execução de testes;
> Não reaproveitamento de funcionalidades;
> Fragilidade, onde qualquer alteração pode ocasionar erros/falhas em diversos pontos;
Ao utilizar os conceitos S.O.L.I.D, a sua aplicação terá vários benefícios da orientação a objetos, como:
> Fácil manutenção, organização, estrutura, design pattern, entendimento ... ;
> Facilidade para aplicação de testes;
> Reaproveitamento de funcionalidades;
> Fácil adaptação de mudanças no escopo do projeto;
---
Todo o conteúdo deste artigo, são para fins de estudos!. A criação deste, tem a finalidade de levar conhecimentos a todos!
#Obrigado!
Tech Manager na Nubank
4 aO mais engraçado é que o Uncle Bob relata que ele não tinha percebido que dava para fazer esse acrônimo quando publicou o artigo dele sobre esses princípios kkk. Ficou muito bom Diego, segue nesse caminho que é só coisa boa pela frente.