Segundo Robert C. Martin, o SRP afirma que:
Nunca deve haver mais de um motivo para uma classe mudar.
No entanto, em seu livro Código Limpo , capítulo 3: Funções, ele mostra o seguinte bloco de código:
public Money calculatePay(Employee e) throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new InvalidEmployeeType(e.type);
}
}
E então afirma:
Existem vários problemas com esta função. Primeiro, é grande e, quando novos tipos de funcionários são adicionados, ele aumenta. Segundo, claramente faz mais de uma coisa. Terceiro, viola o Princípio da Responsabilidade Única (SRP), porque há mais de um motivo para mudar . [ênfase minha]
Em primeiro lugar, pensei que o SRP fosse definido para classes, mas também é aplicável a funções. Em segundo lugar, como essa função tem mais de um motivo para mudar ? Só vejo isso mudando devido a uma alteração no Employee.
Respostas:
Um detalhe frequentemente esquecido do Princípio da Responsabilidade Única é que os "motivos da mudança" são agrupados por atores de casos de uso (você pode ver uma explicação completa aqui ).
Portanto, no seu exemplo, o
calculatePay
método precisará ser alterado sempre que novos tipos de funcionários forem necessários. Como um tipo de funcionário pode não ter nada a ver com outro, seria uma violação do princípio se você os mantivesse unidos, pois a mudança afetaria diferentes grupos de usuários (ou atores de casos de uso) no sistema.Agora, sobre se o princípio se aplica às funções: Mesmo se você tiver uma violação em apenas um método, você ainda está mudando uma classe por mais de um motivo, portanto, ainda assim, é uma violação do SRP.
fonte
Na página 176, capítulo 12: Emergência, na seção intitulada Classes e métodos mínimos, o livro fornece uma correção, afirmando:
e
Obviamente, ele está falando sobre dogmatismo ao seguir o SRP para quebrar perfeitamente pequenos métodos inocentes como
calculatePay()
acima.fonte
Quando Martin aplica o SRP a uma função, ele está implicitamente estendendo sua definição de SRP. Como o SRP é uma formulação específica de OO de um princípio geral, e como é uma boa ideia quando aplicada a funções, não vejo problema com isso (embora possa ter sido bom se ele o incluísse explicitamente no definição).
Também não vejo mais de um motivo para mudar, e não acredito que pensar no SRP em termos de "responsabilidades" ou "razões para mudar" seja útil. Essencialmente, o que o SRP está dizendo é que as entidades de software (funções, classes etc.) devem fazer uma coisa e fazê-lo bem.
Se você der uma olhada na minha definição, ela não é menos vaga do que a redação usual do SRP. O problema com as definições usuais do SRP não é que eles sejam muito vagos, mas que eles tentam ser muito específicos sobre algo que é essencialmente vago.
Se você observar o que
calculatePay
faz, está claramente fazendo uma coisa: despacho com base no tipo. Como o Java possui maneiras integradas de fazer o envio baseado em tipo,calculatePay
é deselegante e não-idiomático, portanto deve ser reescrito, mas não pelos motivos declarados.fonte
Você está certo @Enrique. Não importa se é uma função ou um método de uma classe, o SRP significa que nesse bloco de código você faz apenas uma coisa.
A declaração 'motivo para mudar' às vezes é um pouco enganadora, mas se você alterar
calculateSalariedPay
oucalculateHourlyPay
ou o enum deEmployee.type
que precisa alterar esse método.No seu exemplo, a função:
Na minha opinião, não é diretamente uma violação do SRP, pois os casos de comutação e as chamadas não podem ser gravadas mais curtas, se você pensar em Employee e os métodos já existirem. De qualquer forma, é uma violação clara do princípio de aberto-fechado (OCP), pois você deve anexar instruções 'case' se adicionar tipos de funcionários; portanto, é uma implementação ruim: refatorar.
Não sabemos como o 'Dinheiro' deve ser calculado, mas a maneira mais fácil é ter
Employee
como interface e algumas implementações concretas comgetMoney
métodos. Nesse caso, toda a função é desnecessária.Se for mais complicado calculá-lo, pode-se usar o padrão de visitante, que também não é 100% SRP, mas é mais OCP do que um caso de troca.
fonte