O princípio da responsabilidade única baseia-se no princípio da alta coesão. A diferença entre as duas é que uma classe altamente coesa apresenta um conjunto de responsabilidades fortemente relacionadas, enquanto as classes aderentes ao SRP têm apenas uma responsabilidade.
Mas como determinamos se uma classe específica apresenta um conjunto de responsabilidades e, portanto, é altamente coesa ou se possui apenas uma responsabilidade e, portanto, adere ao SRP? Em outras palavras, não é mais ou menos subjetiva, pois alguns podem considerar uma classe muito granular (e, como tal, acreditarão que a classe adere ao SRP), enquanto outros podem considerá-la não granular o suficiente?
design-patterns
single-responsibility
cohesion
user1483278
fonte
fonte
Respostas:
Por que sim, é muito subjetivo e é o assunto de muitos debates acalorados e enfrentados pelos programadores.
Não há realmente nenhuma resposta, e a resposta pode mudar à medida que seu software se torna mais complexo. O que antes era uma única tarefa bem definida pode eventualmente se tornar várias tarefas mal definidas. Isso é sempre o problema também. Como você escolhe a maneira correta de dividir um programa em tarefas?
O único conselho que posso dar é o seguinte: use seu melhor julgamento (e de seus colegas de trabalho). E lembre-se de que os erros podem (geralmente) ser corrigidos se você os detectar em breve.
fonte
Bob Martin (tio Bob), que originou os princípios SOLID dos quais o SRP é o primeiro, diz sobre isso (estou parafraseando, não consigo lembrar as palavras reais):
Se tiver mais de um motivo, não aderirá ao SRP.
fonte
Eu posso lhe dar várias regras de ouro.
fonte
Os Princípios de Responsabilidade Única afirmam que cada módulo de software deve ter apenas um motivo para mudar. Em um artigo recente, o tio Bob explicou "razões para mudar",
Ele explicou ainda o conceito com um exemplo AQUI .
fonte
Para responder a isso, dê um passo atrás e considere a intenção do princípio de responsabilidade única. Por que é um princípio de design recomendado em primeiro lugar?
O objetivo do princípio é "compartimentar" a base de código; portanto, o código relacionado a uma única "responsabilidade" é isolado em uma única unidade. Isso facilita a localização e a compreensão do código e, mais importante, significa que as alterações na "responsabilidade" afetarão apenas uma única unidade de código.
O que você absolutamente nunca deseja em um sistema é quando, quando uma pequena chance, faz com que outra parte do código aparentemente não relacionada falhe ou mude o comportamento. O SRP ajuda a isolar bugs e alterações.
Então, o que é uma "responsabilidade" então? É algo que pode ser concebível mudar independentemente de outras mudanças. Digamos que você tenha um programa que pode salvar algumas configurações em um arquivo de configuração XML e pode lê-las novamente no arquivo. Essa é uma responsabilidade única ou é "carregar" e "salvar" duas responsabilidades diferentes? Qualquer tipo de alteração no formato ou na estrutura do arquivo exigiria alterações na lógica de carregamento e gravação. Portanto, é uma responsabilidade única que deve ser representada por uma única classe. Agora considere um aplicativo que pode exportar alguns dados nos formatos CVS, Excel e XML. Nesse caso, é fácil imaginar que um formato possa mudar sem afetar o outro. Se você decidir alterar o delimitador no formato CVS, ele não deve afetar a saída do Excel.
fonte
OO diz que as classes são um agrupamento de dados, uma funcionalidade. Essa definição deixa muito espaço para interpretação subjetiva.
Sabemos que as classes devem ser definidas de forma clara e fácil. Mas, para definir essa classe, precisamos ter uma noção clara de como uma classe se encaixa no design geral. Sem requisitos do tipo cascata que, paradoxalmente, são considerados um antipadrão ... isso é difícil de alcançar.
Podemos implementar um design de classe com uma arquitetura que funcione na maioria dos casos, como o MVC. Nos aplicativos MVC, assumimos apenas dados, uma interface do usuário e um requisito para que os dois se comuniquem.
Com uma arquitetura básica, é mais fácil identificar casos em que regras de responsabilidade única estão sendo violadas. EG Passando uma instância de um Controle de Usuário para um Modal.
fonte
Apenas para fins de discussão, apresentarei uma aula do JUCE chamada AudioSampleBuffer . Agora, essa classe existe para armazenar um trecho (ou talvez um trecho bastante longo) de áudio. Ele sabe que o número de canais, o número de amostras (por canal), parece estar comprometido com a flutuação IEEE de 32 bits, em vez de ter uma representação numérica variável ou tamanho de palavra (mas isso não é um problema para mim). Existem funções de membro que permitem obter o numChannels ou numSamples e ponteiros para qualquer canal específico. Você pode tornar um AudioSampleBuffer mais longo ou mais curto. Presumo que o primeiro zere o buffer, enquanto o último trunca.
Existem alguns membros particulares dessa classe que são usados para alocar espaço no heap especial que o JUCE usa.
Mas é isso que está faltando no AudioSampleBuffer (e eu tive várias discussões com Jules sobre isso): um membro chamado
SampleRate
. Como poderia estar faltando isso?A única responsabilidade que um AudioSampleBuffer precisa cumprir é representar adequadamente o áudio físico que se ouve que suas amostras representam. Quando você insere um AudioSampleBuffer de algo que lê um arquivo de som ou de um fluxo, há um parâmetro adicional que você deve obter e passá-lo junto com o AudioSampleBuffer para métodos de processamento (por exemplo, é um filtro) que precisa conhecer a taxa de amostragem ou, eventualmente, para um método que reproduz o buffer para ser ouvido (ou o transmite para outro lugar). Tanto faz.
Mas o que você precisa fazer é continuar passando esse SampleRate, que é inerente ao áudio específico que está no AudioSampleBuffer, em todos os lugares. Eu vi código em que uma constante 44100.0f foi passada para uma função, porque o programador não parecia saber mais o que fazer.
Este é um exemplo de falha no cumprimento de sua única responsabilidade.
fonte
Uma maneira concreta pode ser feita, com base no que você disse - que a alta coesão leva a uma única responsabilidade que você pode medir a coesão. Uma classe coesa máxima possui todos os campos usados em todos os métodos. Embora nem sempre seja possível nem desejável uma classe coesa máxima, ainda é melhor chegar a isso. Tendo esse objetivo de design de classe, é muito fácil deduzir que sua classe não pode ter muitos métodos ou campos (alguns dizem no máximo 7).
Outra maneira é o básico do OOP - modelo após objetos reais. É muito mais fácil ver a responsabilidade dos objetos reais. No entanto, se o objeto real for muito complexo, divida-o em vários objetos contendo cada um deles com sua própria responsabilidade.
fonte