Single Responsibility Principle, também conhecido como Princípio da Responsabilidade Única.
Este é o primeiro princípio do SOLID, um dos mais fáceis de entender e de aplicar.
"A class should have one, and only one, reason to change"
“Uma classe deve ter um, e apenas um, motivo para ser modificada”
Se uma classe só deve ter um motivo para ser modificada, certamente ela só deve ter uma única responsabilidade, logo:
Cada responsabilidade deve ser uma classe, porque uma responsabilidade é um eixo de mudança.
Veja esta classe:
public class DebitoContaCorrente { public void ValidarSaldo(int valor) { } public void DebitarConta(int valor) { } public void EmitirComprovante() { } }
O que esta classe faz?
Esta classe valida saldo em conta e debita valor da conta e emite comprovante.
Esta classe possui três responsabilidades, ou seja, ela tem três razões para ser modificada, problemas a vista, vamos imaginar que por algum motivo a regra de negócio da emissão de comprovante mudou, logo para aplicar a nova regra seria necessário modificar a classe DebitoContaCorrente.
Se por um acaso na modificação da classe algum bug não identificado foi para a produção não apenas a emissão de comprovante, mas sim todas as funcionalidades da classe poderiam estar comprometidas. O sistema deixaria de fazer o débito devido um problema com o comprovante.
Esse é apenas um exemplo de como o acoplamento pode trazer problemas, testes de unidade seriam muito mais complexos de serem desenvolvidos (e menos eficazes).
Ao modificar esta classe vários testes de integração necessitariam ser executados para garantir que uma funcionalidade não comprometeu as demais.
Alguns benefícios do Single Responsibility Principle:
- Complexidade do código reduzida, mais explícita e direta;
- Facilitação da legibilidade;
- Redução de acoplamento;
- Código limpo e testável;
- Facilidade de evolução.
Como deveria ser?
Veja como a classe poderia ficar após um refactoring de aplicação do Single Responsibility Principle:
public class DebitoContaCorrente { public void DebitarConta(int valor) { } } public class SaldoContaCorrente { public void ValidarSaldo(int valor) { } } public class ComprovanteContaCorrente { public void EmitirComprovante() { } }
Cada classe com sua responsabilidade.
No início isso pode parecer exagero, mas não é, isto é uma promoção da qualidade do código e uma ótima maneira de obter os benefícios citados acima.
Conclusão
O Single Responsibility Principle é um dos mais importantes princípios do SOLID, deve ser aplicado para obtermos classes mais coesas e de baixo acoplamento.
Este é o tipo de princípio que todo código orientado a objetos deveria possuir.
Portanto antes de construir aquela classe que cadastra o usuário e envia o e-mail, lembre-se deste princípio.
Referências
Show! Gostei da abordagem, tornou muito mais fácil de compreender.
Parabens!
Muito obrigado pelo feedback Evair.
Abraços
Muito bom para classes novas, o que sugere para as existentes?
Assim que possível um refactoring 🙂
Depois de feito é mais complicado modificar, mas vale a pena dependendo dos benefícios obtidos com o refactoring.
Obrigado por comentar.
Não entendi muito bem… Esse princípio só se aplica as classes que possuem lógica de negócio? Caso eu precise combinar essas funcionalidades, onde eu faria isso? No controlador? E onde essas classes ficariam na nossa arquitetura?
Obrigado
Esse principio se aplica a tudo, tudo deve ter uma única responsabilidade.
Métodos, classes, tudo que é responsável por algo deve ser responsável por apenas aquilo que se propõe a fazer (por ex método de cadastro não deve enviar e-mail no final, isto é outra responsabilidade.) Sugiro a leitura dos links de referencia no artigo 🙂
Gostei, boa explicação.
Pingback: Orientação a Objeto – SOLID | RDR Blog
Então entendi o principio, mas da forma que ficou colocado parece que cada classe sempre terá apenas um método o que não é bem assim, poderia me dar um exemplo desse principio com mais de um metodo na mesma classe?
Não sei se minha resposta vai te ajudar mas…
Uma forma simples seria por exemplo você ter uma classe para operações matemáticas, onde a classe poderia ser algo como Operacoes e dentro você teria os métodos somar(), subtrair(), multiplicar(), dividir() e etc. Todos são métodos de uma mesma classe com o mesmo “princípio”, que é fazer alguma operação entre números e etc…
Não sei se fui claro mas é mais ou menos por aí…
Pingback: AngularJS 2.0 - Conhecendo os serviços - Nicolas Takashi
Pingback: Entendendo a arquitetura multicamadas – GetBlogName();
Ótima explicação e nos exemplos também.
Só para ver se eu entendi o conceito. Se quisermos fazer por exemplo, classes com operações matemáticas: somar(), subtrair(), multiplicar(), dividir(). Temos que fazer 04 classes, uma classe para cada operação, conforme abaixo:
public class OperacaoSomar
2
{
3
public void Somar(int valor, int valorSoma) { }
4
}
5
6
public class OperacaoSubtrair
7
{
8
public void Subtrair(int valor, int valorSub ) { }
9
}
10
11
public class OperacaoMultiplicar
12
{
13
public void Multiplicar(int valor, int valorMult) { }
14
}
public class OperacaoDividir
12
{
13
public void Dividir(int valor, int valorDiv) { }
14
}
Pingback: Arte da Guerra e Desenvolvimento de Softwares | Desenvolvedor Matteus
Pingback: Introdução a Arquitetura Multicamadas – CODETUDE
Certo, acho que eu entendi o conceito. Me esclareça, por gentileza.
Supondo que tenho uma classe PEDIDO, qual das opções abaixo viola o SRP? Por que?
A- Pedido.AdicionarItem();
B- Pedido.AplicarDesconto();
C- Pedido.SalvarDados();
D- Pedido.ReprogramarEntrega();
E- Pedido.Cancelar();
Minha alternativa neste caso seria a letra A, pois entendo que a classe em questão possui apenas o método SalvarDados(), já que trata-se de uma solicitação de pedido. Estou correto?
Obrigado pela ajuda desde já.
Pingback: Arte da Guerra e Desenvolvimento de Softwares | Matteus Barbosa
Minha duvida, por exemplo estou desenvolvendo um sistema de envio e recebimento TCPsocket e listen, mas tenho uma classe que faz as duas coisas, porém preciso por um tempo manter essas informações abertas no server, eu teria que separar esses callbacks como classes separadas ou devo classificar apenas como uma classe network que envia e recebe?