SOLID é um acrônimo que facilita o desenvolvimento de softwares, tornando-os fáceis de manter e estender.
São cinco princípios básicos de programação e design orientados a objetos, que aplicados em conjunto, o desenvolvedor é capaz de escrever um código de fácil manutenção.
Criado por por Michael Feathers, após observar os cinco princípios da orientação a objetos elaborados por Robert C. Martin (Uncle Bob).
Seguem abaixo:
-Single Responsibility Principle (Responsabilidade Única)
–Open/Closed Principle (Aberto/Fechado)
–Liskov Substitution Principle (Substituição de Liskov)
–Interface Segregation Principle (Segregação de Interfaces)
–Dependency Inversion Principle (Inversão de Dependência)
1. SRP — Single Responsibility:
“Uma classe deve ter um, e somente um, motivo para mudar.”
(Robert C. Martin)
Esse princípio declara que uma classe deve ser especializada em um único assunto e possuir apenas uma responsabilidade dentro do software, ou seja, a classe deve ter uma única tarefa ou ação para executar.
Por vezes, sem percebermos, damos a uma classe mais de uma responsabilidade e acabamos criando classes que fazem de tudo.
O foco desse princípio é a coesão, onde quanto melhor definido o que sua classe faz, mais coesa ela é.
Exemplo prático do SRP:
Errado:
Certo:
Como podemos observar, o método add não deveria saber como escrever o log. A saída conforme esse princípio, é criar uma classe de log (FileLogger) com a responsabilidade da escrita.
2. OCP — Open-Closed:
“You should be able to extend a classes behavior, without modifying it.” (Robert C. Martin)
Objetos ou entidades devem estar abertos para extensão, mas fechados para modificação. Esse princípio diz que podemos estender o comportamento de uma classe por meio de herança, interface e composição.
Abaixo dois exemplos onde um viola esse princípio e o outro como deveria ser de acordo com esse princípio.
Exemplo prático do OCP:
Errado:
Certo:
Nos exemplos acima, temos dois tipos de customer, e caso tenhamos a necessidade de adicionar mais um, teríamos que alterar a classe Customer.
A saída foi criar uma classe base (CustomerBetter), com o método Add como virtual, que é sobrescrito pelas classes filhas ExistingCustomer e AnotherCustomer. Dessa forma, cada classe filha pode implementar o método Add conforme sua necessidade.
A vantagem do princípio OCP é a facilidade em inserir novos requisitos reduzindo as chances de novos bugs, já que o novo comportamento é codificado de forma isolada.
3. LSP — Liskov Substitution:
“Derived classes must be substitutable for their base classes.”
(Robert C. Martin)
No princípio da Substituição de Liskov (LSP) diz que “Os subtipos devem ser substituíveis pelos seus tipos base”. Esse princípio foi escrito pela pesquisadora Barbara Liskov em 1988.
Abaixo um exemplo para o entendimento:
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
Exemplo prático Liskov Substitution
Errado:
Certo:
Reparem que na classe Enquiry (que herda de Customer), o método Add não é permitido. Caso fôssemos criar uma lista de Customer, adicionar objetos de tipo de suas filhas e chamar o método Add, uma exceção seria lançada.
Para não ferirmos esse princípio, foi abstraído o conceito de quem pode ser adicionado, criando a classe pai BetterCustomer, que é base para as classes BetterGoldCustomer e BetterSilverCustomer. Dessa forma o foreach do exemplo não gerará erro.
O princípio de Liskov Substitution nos permite usar o polimorfismo com mais confiança. Podemos chamar nossas classes derivadas referindo-se à sua classe base sem preocupações com erros inesperados.
4. ISP — Interface Segregation:
“Make fine grained interfaces that are client specific.”
(Robert C. Martin)
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á utilizar. Esse princípio basicamente diz que é melhor criar interfaces mais específicas ao invés de termos uma única interface genérica.
Exemplo prático do princípio de Segregação da Interface
Errado:
Certo:
Observem que a Interface ICustomerImproved possui os métodos Add E Read, sendo que o método Add já existe na Interface ICustomer.
A idéia é então criar uma nova Interface, como a ICustomerV1, com apenas a assinatura Read.
Por fim, podemos observar a criação da Classe CustomerWithRead que implementa as duas interfaces, cada qual com as assinaturas que devem ser implementadas.
5. DIP — Dependency Inversion:
“Depend on abstractions, not on concretions.“
Robert C. Martin
O princípio da Inversão de Dependências (DIP), diz que devemos “depender de abstrações e não de classes concretas”. Uncle Bob quebra a definição desse princípio em dois sub-itens:
- “Módulos de alto nível não devem depender de módulos de baixo nível.”
- “As abstrações não devem depender de detalhes. Os detalhes devem depender das abstrações.”
Abstrações mudam menos e facilitam a alteração de comportamento e as futuras evoluções.
Em P.O.O. é comum confundirem Inversão de Dependência com a Injeção de Dependência. São coisas distintas que se relacionam com o proposito de deixar o código desacoplado.
Atenção: Inversão de Dependência não é igual a Injeção de Dependência! A Inversão de Dependência é um princípio e a Injeção de Dependência é um Design Pattern.
Exemplo Prático de Inversão de Dependência
Errado:
Certo:
No exemplo, a classe Customer utiliza especificamente como gerador de log a classe FileLogger. Isso é ruim, pois caso quiséssemos usar um outro tipo de logger, teríamos que mexer na classe Customer.
Portanto, a saída é trabalharmos com Interface Ilogger, que vai ser passada no constructor da classe BetterCustomer, não importando o tipo de gerador de log (classe) a ser utilizado.
Fechamos aqui sobre os princípios S.O.L.I.D., e espero que tenham conseguido reforçar os conceitos.
[]’s