S.O.L.I.D

Ao começar a pesquisar sobre SOLID, foi possível encontrar muito conteúdo sobre o clássico Metal Gear Solid. Porém, calma lá! Ele não tem nada a ver com o que vamos falar a seguir. Apesar de ser uma excelente opção de entretenimento para os embalos de sábado à noite! Nosso SOLID trata-se de um acrônimo para os cinco princípios da programação orientada para objetos. E, se você é um amigo programador, com certeza já ouviu falar dele ou mesmo que não lembre de cara pela sigla, com toda certeza o utiliza diariamente em seus projetos.

SOLID para os íntimos ou Single responsibility, Open-closedLiskov substitution, Interface segregation and Dependency inversion.

Foi criado para que um projeto seja realmente orientado a objetos, ao invés de um fruto sem rumo, pé ou cabeça.

Vamos ver a seguir o que cada um desses princípios tratam, com alguns exemplos em linguagem JAVA¹ e outros em Ruby²:

Single Responsibility

O Single responsibility está ligado diretamente ao objetivo que a cada classe possui, sendo que uma classe deve ter sempre um único objetivo. Se o sistema está crescendo e uma classe passou a ter duas responsabilidades é hora de dividi-la em duas classes, cada uma com uma responsabilidade. Exemplo:

Imagine um formulário de cadastro onde o usuário ao submeter os dados já faz o upload do arquivo anexo e envia um e-mail para o mesmo confirmando o cadastro. A responsabilidade de salvar ficou na classe do cliente enquanto fazer o upload e enviar o e-mail ficaram em classes separadas, podendo ser utilizados em outros lugares do sistema em que seja necessário novamente fazer o upload de um arquivo como no cadastro de produtos ou enviar um e-mail como no fechamento de uma compra.

 

Open-closed

O princípio de aberto e fechado nos traz o conceito de que devemos sempre deixar nossas classes abertas para serem expandidas, porém fechadas para serem modificadas. Ou seja, você deve isolar a regra para que assim outras classes possam usar ela. Exemplo:

No exemplo acima sempre que implementarmos alguma regra nova, por exemplo um Fornecedor (Provider), iremos colocar um if a mais no código e esses ifs tendem ao infinito.

A ideia do princípio é colocar a role em uma interface para retirar esses ifs. Exemplo:


Desta forma dentro das classes iremos implementar o método
 executeRole sem nenhum if, apenas executando o que cada um deveria fazer. A ideia nesse caso é que a interface Role seja pouco modificada (o ideal é que ela não seja modificada) e apenas a sua implementação nas classes que irão utilizá-la sejam alteradas conforme a necessidade da classe.

Liskov substitution

Esse princípio está relacionado a herança e diz que se você tem um objeto B que herda A, em qualquer lugar que você tenha A você pode substituir por B sem precisar alterar o programa. Exemplo:

 

Basicamente temos uma classe Gadget e ela possui um método de call (ligar), sendo que Smartphone e PSP são Gadgets, logo herdam ela e trazem consigo o método call. Porém, o PSP não faz ligações, por isso mesmo faremos o método retornar uma exception. Com isso ferimos o princípio de Liskov.

Se tivéssemos uma instância de Gadget e a mesma fosse substituída por Smartphone funcionaria normalmente. O método call, ao invés de ter um retorno booleano, como o método da classe pai fazia, acaba retornando uma exception (claro que poderíamos fazer o método call no PSP, mas queria deixar dessa forma, como um exemplo).

 

– Interface segregation

O Princípio da Segregação de Interface trata da coesão de interfaces e diz que classes não devem ser forçadas a depender de métodos que não usam. Exemplo:

Esse exemplo está ferindo o princípio, pois o dono da loja pode comprar do fornecedor e o cliente comprar do dono da loja, mas o fornecedor não compra de ninguém e, nesse caso, você seria obrigado a implementar o método buy no fornecedor, mesmo o método não servindo para ele.

Dependency inversion

O princípio de inversão de dependência nos diz que SE devemos acoplar alguma classe em outra, devemos fazer esse acoplamento em classes estáveis. De forma mais simples o princípio quer dizer:

  • 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.

Exemplo:

Nesse exemplo o carrinho é um módulo de alto nível e o ActionAfterBuy (Ação depois de comprar) é uma abstração. Perceba que o ActionAfterBuy é uma classe estável, pelo fato de que ela pouco vai ser alterada ao longo do tempo (a ideia de classes estáveis é justamente essa, não alterá-la durante o ciclo de vida do software); além disso, ela não conhece detalhes de sua própria implementação.

Esse é apenas um resumo do que é o SOLID, caso queira se aprofundar no assunto, recomendo fortemente o livro “Orientação a Objetos e SOLID para ninjas” do Maurício Aniche. Outro bom artigo é o “The Principles of OOD”. hiperlink: http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

 

¹ JAVA –  Linguagem de programação orientada a objetos desenvolvida na década de 90 por uma equipe de programadores chefiada por James Gosling, na empresa Sun Microsystems – mais informações: (hiperlink) https://pt.wikipedia.org/wiki/Java_(linguagem_de_programa%C3%A7%C3%A3o).

² Ruby – Linguagem de programação interpretada multiparadigma, de tipagem dinâmica e forte, com gerenciamento de memória automático, originalmente planejada e desenvolvida no Japão em 1995 – mais informações: (hiperlink) https://pt.wikipedia.org/wiki/Ruby_(linguagem_de_programa%C3%A7%C3%A3o).