segunda-feira, 24 de julho de 2017

O princípio da responsabilidade única - S.O.L.I.D

Olá ! Meu nome é João Paulo Maida e bem-vindos ao blog Preciso Estudar Sempre.

Pare por um instante e reflita sobre a seguinte frase:


Uma classe deve ter somente um único motivo para mudar. (MARTIN, ROBERT; MARTIN MICAH)


Este é o princípio da responsabilidade única (Single-Responsibility Principle - SRP em inglês) e se você for um iniciante no mundo da programação e achar esta declaração estranha, não se espante. Este conceito não é banal e tampouco é ensinado na faculdade, logo sua reação é normal. Na verdade, são poucos os programadores que sabem do que estou falando e isto de fato é preocupante, visto que o conceito que iremos discutir aqui hoje forma um dos pilares do que realmente a orientação a objetos trata.

Voltando à frase, conseguiu pensar ? Conseguiu ver a quantidade de conhecimento preso em uma única frase ? Não !? Bem, minha meta é abrir sua mente para o verdadeiro desafio de se construir software orientado a objetos.

Análise a situação abaixo.
Figura 1 - Modelo de classes acoplado

A classe AbridorDeGarrafas tem como responsabilidade abrir garrafas, sejam elas com tampa metálica, usadas nas garrafas de cerveja, ou com rolha de cortiça, usadas nas garrafas de vinho. Os objetos Taverna e Adega dependem destes métodos para funcionar. Queremos realizar uma modificação na implementação do método de abrir garrafas com tampa metálica sem causar impacto no funcionamento do método que abre garrafas com rolha. Será que isto é possível ? Não é preciso muito tempo para ver que a resposta é não porque será necessário recompilar, retestar e reimplantar todo este modelo para que esta mudança não resulte em problemas posteriores.

Então como alterar algo sem mexer no que já funciona ? Lembre-se que hoje somente o objeto Adega depende de AbridorDeGarrafas, mas amanhã pode existir uma gama de objetos com esta mesma dependência. Então, o que fazer ?

Isto tudo acontece por um único motivo, a classe AbridorDeGarrafas possui mais de 1 responsabilidade e tal nos leva a um modelo altamente acoplado, onde as mudanças feitas em um método afetam o funcionamento do outro. Isso é péssimo e não pode continuar 👎. Tudo isto fere o princípio da responsabilidade única, então a pergunta que nos sobra é: como corrigir o problema ?

Simples ! Devemos separar as responsabilidades da classe AbridorDeGarrafas. Entenda como responsabilidade uma razão para mudar e aqui existem duas para isso, são elas: atender solicitações de abertura de garrafas com tampa metálica e atender solicitações de abertura de garrafas com rolha. Entender essa separação é crucial para a montagem de um design que é ao mesmo tempo robusto e flexível, mas separar não significa que uma classe só deve conter um único método. Ao contrário, ela pode conter quantos métodos quiser desde que todos estejam relacionados a mesma responsabilidade. A partir do momento em que identificamos uma nova responsabilidade, a separação deve acontecer. Eis como o nosso modelo fica.
Figura 2 - Modelo de classes altamente coeso

Agora temos duas classes, uma que só abre garrafas com tampa metálica e outra que só abre garrafas com rolha e cada uma possui um método chamado abrirGarrafa(). Não há mais necessidade de especificar no nome do método que aquela abertura de garrafa é com tampa metálica ou de rolha, pois o nome da classe já tem essa expressividade. É dedutível que o abrirGarrafa() da classe AbridorDeGarrafasComTampaMetalica só abre garrafas com tampa metalica. Dessa forma podemos realizar quais mudanças quisermos sem afetar o que já funciona e isto é ótimo 👍.

Contudo, ainda falta um ponto para se pensar. Sempre que identificarmos mais de uma responsabilidade ela deve ser separada ? Levantar essa dúvida a esta altura pode parecer antagônico, mas não é. Este princípio é um dos mais difíceis e todos os outros da plataforma S.O.L.I.D se remetem à ele, logo esta indagação faz sentido e para respondê-la devemos levar em conta o contexto. Se uma alteração implica em mudar o todo não há necessidade de separar responsabilidades, pois para aquele contexto aquilo consiste uma única responsabilidade. Profundo, não !? 😕

Considere o seguinte exemplo: suponha que ao invés da mudança ser na abertura de garrafas com tampas metálicas, ela seria a adição de um mecanismo que melhora o encaixe do abridor na garrafa. Realmente deveríamos separar as responsabilidades aqui visto que a alteração afeta o todo ? A resposta é não, logo não faz sentido. Não existe uma fórmula mágica para todas as situações, cada uma deve ser avaliada separadamente.

Chegamos ao fim de mais um post. Nas próximas publicações veremos mais princípios da plataforma S.O.L.I.D e como eles se complementam. Como já é de costume, se inscreva no blog e no canal do youtube para ficar por dentro das novidades, indique para seus amigos e compartilhe em suas redes sociais.

Até a próxima minha boa gente ! 😘

Leia nossa postagem anterior: O algoritmo de Dijkstra - Grafos

Dúvidas !? Sugestões ?! Críticas ou elogios ?!

Deixe aí nos comentários, envie um e-mail ou uma mensagem na nossa página do Facebook.

E-mail: precisoestudarsempre@gmail.com
Facebook: https://www.facebook.com/precisoestudarsempre/
Canal Preciso Estudar Sempre: https://www.youtube.com/channel/UCUoW8dS38rXr0a5jWU57etA

Referências

MARTIN, ROBERT; MARTIN MICAH; Agile Principles, Patterns and Practices in C#; 2006

4 comentários:

Anônimo disse...

Muito bem explicado e conciso. Parabéns

Anônimo disse...

Obrigado pelos ótimos conteudos.

Anônimo disse...

Por que não usar interface?

Preciso estudar sempre disse...

Explica melhor sua dúvida.