O que é SOLID: O guia completo para você entender os 5 princípios da POO

Alterar uma classe já existente para adicionar um novo comportamento, corremos um sério risco de introduzir bugs em algo que já estava funcionando.

Lembre-se: OCP preza que uma classe deve estar fechada para alteração e aberta para extensão.

Como adicionamos um novo comportamento sem alterar o código fonte já existente?O guru Uncle Bob resumiu a solução em uma frase:Separate extensible behavior behind an interface, and flip the dependencies.

Em tradução direta, seria:Separe o comportamento extensível por trás de uma interface e inverta as dependências.

O que devemos fazer é concentrar nos aspectos essencias do contexto, abstraindo-os para uma interface.

Se as abstrações são bem definidas, logo o software estará aberto para extensão.

Aplicando OCP na práticaVoltando para o nosso exemplo, podemos concluir que o contexto que estamos lidando é a remuneração dos contratos de trabalho, aplicando as premissas de se isolar o comportamento extensível atrás de uma interface, podemos criar uma interface com o nome Remuneravel contendo o método remuneracao(), e fazer com que nossas classes de contrato de trabalho implementem essa interface.

Além disso, iremos colocar as regras de calculo de remuneração para suas respectivas classes, dentro do método remuneracao(), fazendo com que a classe FolhaDePagamento dependa somente da interface Remuneravel que iremos criar.

Veja o código refatorado abaixo:Agora a classe FolhaDePagamento não precisa mais saber quais métodos chamar para calcular.

Ela será capaz de calcular o pagamento corretamente de qualquer novo tipo de funcionário que seja criado no futuro (ContratoPJ) — desde que ele implemente a interface Remuneravel — sem qualquer necessidade de alteração do seu código fonte.

Dessa forma, acabamos de implementar o princípio de Aberto-Fechado do SOLID em nosso código!Open-Closed Principle também é base para o padrão de projeto Strategy — Falerei desse padrão em um próximo artigo.

Particularmente esse é o princípio que eu mais admiro, a sua principal vantagem é a facilitade na adição de novos requisitos, diminuindo as chances de introduzir novos bugs — ou bugs de menor expresão — pois o novo comportamento fica isolado, e o que estava funcionando provavelmente continuara funcionando.

3.

LSP— Liskov Substitution Principle:Princípio da substituição de Liskov — Uma classe derivada deve ser substituível por sua classe base.

O princípio da substituição de Liskov foi introduzido por Barbara Liskov em sua conferência “Data abstraction” em 1987.

A definição formal de Liskov diz que:Se para cada objeto o1 do tipo S há um objeto o2 do tipo T de forma que, para todos os programas P definidos em termos de T, o comportamento de P é inalterado quando o1 é substituído por o2 então S é um subtipo de TUm exemplo mais simples e de fácil compreenção dessa definição.

Seria:se S é um subtipo de T, então os objetos do tipo T, em um programa, podem ser substituídos pelos objetos de tipo S sem que seja necessário alterar as propriedades deste programa.

 — Wikipedia.

Para facilitar o entendimento, veja esse princípio na prática neste simples exemplo:Estamos passando como parametro tanto a classe pai como a classe derivada e o código continua funcionando da forma esperada.

Exemplos de violação do LSP:Sobrescrever/implementar um método que não faz nada;Lançar uma exceção inesperada;Retornar valores de tipos diferentes da classe base;Para não violar o Liskov Substitution Principle, além de estruturar muito bem as suas abstrações, em alguns casos, você precisara usar a injeção de dependencia e também usar outros princípios do SOLID, como por exemplo, o Open-Closed Principle e o Interface Segregation Principle — será abordado no próximo tópico.

Seguir o LSP nos permite usar o polimorfismo com mais confiança.

Podemos chamar nossas classes derivadas referindo-se à sua classe base sem preocupações com resultados inesperados.

4.

ISP — Interface Segregation Principle:Princípio da Segregação da Interface — Uma classe não deve ser forçada a implementar interfaces e métodos que não irão utilizar.

Esse princípio basicamente diz que é melhor criar interfaces mais específicas ao invés de termos uma única interface genérica.

Vamos ver o ISP na prática através de códigos:Em um cenário fictício para criação de um game de animais, teremos algumas aves que serão tratadas como personagens dentro do jogo.

Sendo assim, criaremos uma interface Aves para abstrair o comportamento desses animais, depois faremos que nossas classes implementem essa interface, veja:Percebam que ao criar a interface Aves, atribuimos comportamentos genéricos e isso acabou forçando a classe Pinguim a implementar o método setAltitude()do qual ela não deveria ter, pois pinguins não voam!.Dessa forma, estamos violando o Interface Segregation Principle — E o LSP também!Para resolver esse problema, devemos criar interfaces mais específicas, veja:No exemplo acima, retiramos o método setAltitude() da interface Aves e adicionamos em uma interface derivada AvesQueVoam.

Isso nos permitiu isolar os comportamentos das aves de maneira correta dentro do jogo, respeitando o princípio da segregação das interfaces.

Poderiamos melhor ainda mais esse exemplo, criando uma interface Renderizavel pra abstratir esse comportamento, mas o foco aqui é explicar o conceito e não desenvolver o game, então vamos para o próximo princípio.

5.

DIP — Dependency Inversion Principle:Princípio da Inversão de Dependência — Dependa de abstrações e não de implementações.

De acordo com Uncle Bob, esse princípio pode ser definido da seguinte forma:1.

Módulos de alto nível não devem depender de módulos de baixo nível.

Ambos devem depender da abstração.

2.

Abstrações não devem depender de detalhes.

Detalhes devem depender de abstrações.

No contexto da programação orientada a objetivos, é comum que as pessoas confudam a Inversão de Dependência com a Injeção de Dependência, porém são coisas distintas, mas que relacionam entre si com um proposito em comum, deixar o código desacoplado.

Importante: Inversão de Dependência não é igual a Injeção de Dependência, fique ciente disso!.A Inversão de Dependência é um princípio (Conceito) e a Injeção de Dependência é um padrão de projeto (Design Pattern).

Vamos entender tudo isso na prática através de exemplos:Para recuperar a senha, a classe PasswordReminder, precisa conectar na base de dados, por tanto, ela cria um instancia da classe MySQLConnection em seu método construtor para realizar as respectivas operações.

Nesse pequeno trecho de código temos um alto nível de acoplamento, isso acontece porque a classe PasswordReminder tem a responsabilidade de criar uma instância da classe MySQLConnection!.Se quiséssemos reaproveitar essa classe em outro sistema, teriamos obrigatoriamente de levar a classe MySQLConnection junto, portanto, temos um forte acoplamento aqui.

Para resolver esse problema de acoplamento, podemos refatorar nosso código da seguinte forma.

Veja:Com o código refatorado, a criação do objeto MySQLConnection deixa de ser uma responsabilidade da classe PasswordReminder, a classe de conexão com o banco de dados virou uma dependência que deve ser injetada via método construtor.

Olha o que apareceu para nós: Injeção de Dependência!Apesar de termos usado a injeção de dependência para melhorar o nível de acoplamento do nosso código, ele ainda viola o princípio da inversão de dependência! — lembre-se, um não é igual ao outro.

Além de violar o DIP, se você prestar atenção na forma que o exemplo foi codificado irá perceber que ele também viola o Open-Closed Principle.

Por exemplo, se precisarmos alterar o banco de dados de MySQL para Oracle teriamos que editar a classe PasswordReminder.

Por que nosso exemplo refatorado viola o Dependency Inversion Principle?Porque estamos dependendo de uma implementação e não de uma abstração, simples assim.

De acordo com a definição do DIP, um módulo de alto nível não deve depender de módulos de baixo nível, ambos devem depender da abstração.

Então, a primeira coisa que precisamos fazer é identificar no nosso código qual é o módulo de alto nível e qual é o módulo de baixo nível.

Módulo de alto nível é um módulo que depende de outros módulos.

No nosso exemplo ,PasswordReminder depende da classe MySQLConnection.

Sendo asssim, PasswordReminder é o módulo de alto nível e MySQLConnection é o módulo de baixo nível.

Mas, MySQLConnection é uma implementação e não uma abstração!Como refatoramos nosso exemplo para utilizar o DIP?Se tratando de POO, você já ouviu aquela frase:“Programe para uma interface e não para uma implementação.

”Pois bem, é exatamente o que iremos fazer, criar uma interface!interface DBConnectionInterface{ public function connect();}Agora, vamos refatorar nosso exemplo fazendo que nossos módulos de alto e baixo nível dependam da abstração proposta pela interface que acabamos de criar.

Veja:Perfeito!.Agora a classe PasswordReminder não tem a mínima ideia de qual banco de dados a aplicação irá utilizar.

Dessa forma, não estamos mais violando o DIP, ambas as classes estão desacopladas e dependendo de uma abstração.

Além disso, estamos favorecendo a reusabilidade do código e como “bônus” também estamos respeitando o SRP e o OCP.

ConclusãoA sistemática dos princípios SOLID tornam o software mais robusto, escalável e flexível, deixando-o tolerante a mudanças, facilitando a implementação de novos requisitos para a evolução e manutenção do sistema.

Levando em consideração algumas experiências vividas ao longo da minha história no mundo da tecnologia, acredito que os princípios SOLID, juntamente com algumas técnicas e boas praticas de Clean Code, são fatores essenciais que todos os desenvolvedores deveriam aplicar em seus códigos.

Pode ser um pouco assustador no início usar todos esses princípios — nem sempre conseguiremos aplicar todos em nosso projeto — mas com a prática e constancia, aos poucos vamos adquirindo a experiência necessária para escrever códigos cada vez mais maduros, os princípios SOLID servem como guias pra isso.

Referências:http://butunclebob.

com/ArticleS.

UncleBob.

PrinciplesOfOodhttps://en.

wikipedia.

org/wiki/SOLIDhttps://laracasts.

com/series/solid-principles-in-phphttps://www.

tomdalling.

com/blog/software-design/solid-class-design-the-liskov-substitution-principleArtigos que talves você possa se interessar:#1 — Clean Code: O que é?.Porque usar?Clean Code é uma filosofia de desenvolvimento cuja o principal objetivo é aplicar técnicas simples que visam facilitar…medium.

com#2 — Clean Code: Boas práticas para escrever códigos impecáveis!Na primeira parte desse artigo eu falei um pouquinho sobre o que é Clean Code e qual o real impacto de escrever código…medium.

comEditorConfig : Padronizando a codificação de arquivos entre diferentes editores e IDEs.

EditorConfig é um projeto open-source que facilita a adoção e padronização de um estilo de código para vários editores…medium.

comO que é UUID?.Porque usá-lo?UUID — (do inglês Universally Unique IDentifier )medium.

comAinda não me conhecia?.Então chegou a hora: Olá, meu nome é João Roberto, muito prazer!Primeiros passos: Um pouco da minha história!Conversor de café em código.

Aspirante a empreendedor, apaixonado por tecnologia e investimentos.

Um cara tranquilo e…medium.

comJoão Roberto P.

Borges – Personal SiteJoão Roberto P.

Borges, analista de sistemas e desenvolvedor.

joaorobertopb.

com.

. More details

Leave a Reply