Princípios SOLID: responsabilidade única e aberto/fechado.
SOLID é um acrônimo mnemônico criado por Michael Feathers e popularizados pelo Uncle Bob, Robert C. Martin, que relaciona a cada letra um tópico de boas práticas de programação. A prática destes princípios SOLID visa deixar o projeto mais coeso, reaproveitável e torna a sua manutenção mais fácil.
Este artigo abordará as duas primeiras letras – ou melhor, as duas primeiras práticas –, o Single responsibility principle (princípio da responsabilidade única) e o Open/closed principle (principio aberto/fechado).
![Princípios SOLID solid](https://dtidigital.com.br/wp-content/uploads/2015/10/solid.png)
O princípio da responsabilidade única tem como regra que uma classe deve possuir uma, e apenas uma, responsabilidade. Pode-se traduzir isso em “uma classe deve ter apenas um motivo para mudar”.
Sumário
Por que uma classe deve ter apenas uma responsabilidade?
A reposta é simples: quanto maior o número de responsabilidades, maiores as chances de modificação dessa classe no futuro e maiores as chances de inserção de bugs que atrapalharão a classe por inteiro.
Imaginemos o seguinte exemplo:
#region Código 1
public class Cozinheiro
{
public void fazerPrato(object prato)
{
// código para a realização de pratos
}
public double valorDoPrato(object prato)
{
// código para o calculo do valor do prato
}
public void recolherPratos()
{
// código para recolher os pratos
}
}
#endregion
Esta classe é responsável por preparar o prato e calcular o valor do prato e recolher os pratos. Esses ‘es’ indicam que a nossa classe possui mais de uma responsabilidade, e assim, mais de um motivo para ser modificada. Caso desejássemos modificar a maneira com que os pratos são recolhidos, teríamos que modificar a nossa classe Cozinheiro. Caso esta modificação gerasse algum bug, não apenas a retirada dos pratos, mas sim todas as funcionalidades da classe poderiam estar comprometidas. A classe Cozinheiro deixaria de preparar a comida devido um problema com a retirada de pratos.
Como deveria ser?
A pergunta aqui é: qual a responsabilidade da classe Cozinheiro? Preparar o prato! Perceba que não importam a quantidade de métodos necessários para tal. A ‘responsabilidade única’ está ligada à função da classe, e não à maneira que esta função é implementada. Veja como ficaria a refatoração do código:
#region Código 2
public class Cozinheiro
{
public void fazerPrato(object prato)
{
// código para a realização de pratos
}
}
public class Caixa
{
public double valorDoPrato(object prato)
{
// código para o calculo do valor do prato
}
}
public class Garcon
{
public void recolherPratos()
{
// código para recolher os pratos
}
}
#endregion
A classe Cozinheiro agora possui apenas uma única responsabilidade: preparar o prato. O único motivo para alterar essa classe é caso a forma de preparar o prato seja modificada, reduzindo assim a complexidade, facilitando a legibilidade e reduzindo o acoplamento.
![Princípios SOLID Figura 2 - "Só porque você pode, não significa que você deva"](https://dtidigital.com.br/wp-content/uploads/2015/10/solid2.png)
O princípio aberto/fechado diz que as entidades de software (classes, módulos, funções, etc.) devem estar abertas para extensão, mas fechadas para modificação, ou seja, deve ser possível estender o comportamento de uma classe, mas não a modificar.
Qual a importância deste princípio?
A extensibilidade! É comum a manutenção de códigos. Você deve, então, lidar com as classes já criadas e, possivelmente, adicionar ou remover funcionalidades. Para uma classe ‘não-extensível’, a adição ou remoção de funcionalidades implica na modificação da classe por si só. Ao fazer tal mudança, você estará propenso a fazer com que outras partes do seu código não funcionem mais.
Utilizando a nossa classe Cozinheiro, poderíamos implementar a função de preparar pratos da seguinte forma:
#region Código 3
public class Cozinheiro
{
public void fazerPrato(object prato)
{
if (prato is Omelete)
{
// código para a realização de um omelete
}
if (prato is Macarrao)
{
// código para a realização de um macarrao
}
if (prato is FrangoAssado)
{
// código para a realização de um frango assado
}
}
}
public class Omelete
{
// propriedades do omelete
}
public class Macarrao
{
// propriedades do macarrão
}
public class FrangoAssado
{
// propriedades do frango assado
}
#endregion
Aparentemente, nenhum problema. Mas e se quiséssemos implementar um prato novo? Teríamos que modificar a classe Cozinheiro.
E qual é o problema de um IF a mais na classe?
Ao adicionar outro IF de validação, além de termos que substituir a classe na publicação da nova versão, estaremos correndo o risco de introduzir bugs em uma classe que já estava funcionando.
Assim, para cada prato novo, seriam necessárias novas alterações na classe Cozinheiro, e para cada uma dessas alterações, teríamos que nos assegurar que as funcionalidades anteriores continuassem funcionando e que as novas funcionalidades não interferissem nas antigas.
Então qual é a solução?
A utilização da abstração. A classe pai deve possuir o método exigido (que no nosso caso é o fazerPrato), enquanto os filhos dessa classe devem apenas implementar a forma com que este método será executado. Veja como este princípio seria implementado no exemplo anterior:
#region Código 4
public class Cozinheiro
{
public void fazerPrato(Prato prato)
{
prato.Fazer();
}
}
public abstract class Prato
{
public abstract void Fazer();
}
public class Omelete : Prato
{
// propriedades do omelete
public override void Fazer()
{
// código para a realização de um omelete
}
}
public class Macarrao : Prato
{
// propriedades do macarrao
public override void Fazer()
{
// código para a realização de um macarrao
}
}
public class FrangoAssado : Prato
{
// propriedades do frango assado
public override void Fazer()
{
// código para a realização de um frango assado
}
}
#endregion
Possuímos agora uma abstração bem definida, onde todas as extensões implementam suas próprias regras de negócio sem necessidade de modificar uma funcionalidade devido a remoção, mudança ou inclusão de outra.
Dessa forma a nossa nova classe Cozinheiro está aberta para extensão pois podemos incluir tantos pratos quanto desejarmos, mas está fechada para modificação pois podemos fazer isso sem ter que alterar a classe. Assim, além da independência entre as extensões, o código fica mais claro e a aplicação de testes de unidades fica mais fácil e coesa.
Observe assim que aplicando apenas dois princípios do SOLID em conjunto, aumenta-se bastante as chances de que o sistema criado seja mais claro e simples de estender.
Tem alguma dúvida sobre os princípios SOLID? Entre em contato com a gente.
Por: Victor Castro.
Revisão: Jéssica Saliba.
Desenvolvimento de Software
Confira outros artigos
![](/_next/image?url=https%3A%2F%2Fwww.cms.dtidigital.com.br%2Fwp-content%2Fuploads%2F2024%2F07%2Fmecanismos-de-acompanhamento.webp&w=1024&q=75)
Mecanismos de Acompanhamento no Desenvolvimento de Software
O uso de mecanismos de acompanhamento é imprescindível no mundo do desenvolvimento de software e pode potencializar a eficiência digital. O acompanhamento efetivo das operações é fundamental para garantir a entrega de soluções digitais de sucesso. Na nossa empresa, utilizamos uma metodologia única, o dti evolve, que incorpora inteligência artificial (IA) para acelerar nosso processo de […]
Desenvolvimento de Software
![Fundo de código com celular apresentando eficiência digital com copilot](/_next/image?url=https%3A%2F%2Fwww.cms.dtidigital.com.br%2Fwp-content%2Fuploads%2F2024%2F07%2FGitHub-copilot-eficiencia-dti.webp&w=1024&q=75)
Eficiência digital com copilot: um caso de uso do GitHub
Em um mundo em constante evolução tecnológica, otimizar o tempo e potencializar a eficiência digital se torna cada vez mais crucial. Portanto, vamos apresentar alguns experimentos que estão sendo implementados com o Git Hub Copilot em busca de maior eficiência digital. Certamente quem nos acompanha sabe que estamos experimentando e introduzindo as melhores ferramentas de […]
Desenvolvimento de Software
![Engenharia de Prompt - Como conversar com Ia](/_next/image?url=https%3A%2F%2Fwww.cms.dtidigital.com.br%2Fwp-content%2Fuploads%2F2024%2F07%2FShutterstock_2422157137-1.png&w=1024&q=75)
Engenharia de Prompt: A Arte de Conversar com a IA
Sumário1 Falando a Linguagem das Máquinas2 O que é Engenharia de Prompt?3 A Importância da Engenharia de Prompt em Ação: Aplicações do Mundo Real 4 Princípios-chave da Engenharia de Prompt Eficaz4.1 Desconstruindo o Prompt:4.2 Técnicas de Engenharia de Prompt:4.3 Combinando Técnicas e Criando sua Obra-Prima:5 As Armadilhas da Engenharia de Prompt: Navegando pelos Limites dos Modelos […]
Desenvolvimento de Software