Le principe de responsabilité unique repose sur le principe de haute cohésion. La différence entre les deux réside dans le fait qu’une classe très cohérente comporte un ensemble de responsabilités étroitement liées, tandis que les classes adhérant au PRS n’ont qu’une responsabilité.
Mais comment déterminer si une classe particulière comporte un ensemble de responsabilités et est donc simplement très cohérente, ou si elle n’a qu’une responsabilité et adhère donc au PRS? En d'autres termes, n'est-il pas plus ou moins subjectif, puisque certains peuvent considérer une classe comme très granulaire (et en tant que telle croiront que la classe adhère au PRS), tandis que d'autres peuvent le considérer comme n'étant pas assez granulaire?
design-patterns
single-responsibility
cohesion
utilisateur1483278
la source
la source
Réponses:
Pourquoi oui, c’est très subjectif, et c’est le sujet de nombreux débats houleux et virulents dans lesquels les programmeurs se lancent.
Il n'y a pas vraiment de réponse unique, et la réponse peut changer à mesure que votre logiciel devient plus complexe. Ce qui était autrefois une tâche unique bien définie peut éventuellement devenir plusieurs tâches mal définies. C'est toujours le problème aussi. Comment choisissez-vous la bonne façon de diviser un programme en tâches?
Le seul conseil que je puisse vous donner est le suivant: utilisez votre meilleur jugement (et celui de vos collègues). Et rappelez-vous que les erreurs peuvent (généralement) être corrigées si vous les corrigez assez tôt.
la source
Bob Martin (Oncle Bob), à l'origine des principes SOLID dont SRP est le premier, dit à ce propos (je me paraphrase, je ne me souviens plus des mots):
S'il a plus d'une raison, il n'adhère pas à SRP.
la source
Je peux vous donner plusieurs règles de base.
la source
Selon les principes de responsabilité unique, chaque module logiciel ne doit avoir qu'une seule raison de changer. Dans un article récent, oncle Bob a expliqué "raison de changer",
Il a ensuite expliqué le concept avec un exemple ICI .
la source
Pour répondre à cette question, prenez du recul et considérez l’ intention du principe de responsabilité unique. Pourquoi est-ce un principe de conception recommandé en premier lieu?
Le but du principe est de "compartimenter" la base de code, de sorte que le code relatif à une "responsabilité" unique soit isolé dans une seule unité. Cela facilite la recherche et la compréhension du code et, plus important encore, cela signifie que les modifications apportées à la "responsabilité" n'auront une incidence que sur une seule unité de code.
Ce que vous ne voulez absolument jamais dans un système, c’est quand une petite chance fait échouer une autre partie du code apparemment non liée ou modifier son comportement. Le SRP aide à isoler les bugs et les changements.
Alors qu'est-ce une "responsabilité" alors? C'est quelque chose qui pourrait éventuellement changer indépendamment des autres changements. Supposons que vous ayez un programme capable de sauvegarder certains paramètres dans un fichier de configuration XML et de les relire à partir du fichier. Est-ce une responsabilité unique ou est-ce que "charger" et "sauver" sont deux responsabilités différentes? Toute modification du format ou de la structure du fichier nécessiterait de modifier la logique de chargement et de sauvegarde. C'est donc une responsabilité unique qui devrait être représentée par une classe unique. Considérons maintenant une application qui peut exporter des données au format CVS, Excel et XML. Dans ce cas, il est facile d'imaginer qu'un format puisse changer sans affecter l'autre. Si vous décidez de modifier le délimiteur au format CVS, cela ne devrait pas affecter la sortie Excel.
la source
OO dit que les classes sont un groupement de données et une fonctionnalité. Cette définition laisse beaucoup de place à une interprétation subjective.
Nous savons que les classes doivent être définies clairement et facilement. Mais, pour définir une telle classe, nous devons avoir une idée claire de la façon dont une classe s’intègre dans la conception globale. Sans exigences de type cascade qui, paradoxalement, sont considérées comme des anti-modèles ... cela est difficile à réaliser.
Nous pouvons implémenter une conception de classe avec une architecture qui fonctionne dans la plupart des cas, comme MVC. Dans les applications MVC, nous supposons que nous n’avons que des données, une interface utilisateur et une obligation pour les deux personnes de communiquer.
Avec une architecture de base, il est plus facile d'identifier les cas où des règles de responsabilité unique sont enfreintes. EG Passage d'une instance d'un contrôle utilisateur à un modal.
la source
Juste pour les besoins de la discussion, je vais aborder un cours de JUCE appelé AudioSampleBuffer . Maintenant, cette classe existe pour contenir un extrait (ou peut-être un extrait assez long) d'audio. Il connaît le nombre de canaux, le nombre d'échantillons (par canal), semble être affecté à la méthode float IEEE 32 bits plutôt que d'avoir une représentation numérique variable ou une taille de texte (mais ce n'est pas un problème pour moi). Il existe des fonctions membres qui vous permettent d’obtenir numChannels ou numSamples et des pointeurs sur un canal particulier. Vous pouvez créer un AudioSampleBuffer plus long ou plus court. Je présume que les premiers tamponnent le tampon pendant que les derniers tronquent.
Quelques membres privés de cette classe sont utilisés pour l'allocation d'espace dans le tas spécial utilisé par JUCE.
Mais c’est ce qui manque à AudioSampleBuffer (et j’ai eu plusieurs discussions à ce sujet avec Jules): un membre a appelé
SampleRate
. Comment cela pourrait-il manquer?La seule responsabilité qu'un AudioSampleBuffer doit remplir est de représenter correctement le son physique que l'on entend que ses échantillons représentent. Lorsque vous entrez un AudioSampleBuffer à partir de quelque chose qui lit un fichier son ou un flux, vous devez obtenir un paramètre supplémentaire et le transmettre avec les méthodes de traitement AudioSampleBuffer aux méthodes de traitement (disons qu'il s'agit d'un filtre) qui doit connaître le taux d'échantillonnage ou, finalement, à une méthode qui lit la mémoire tampon pour la faire entendre (ou la diffuse vers un autre endroit). Peu importe.
Mais ce que vous devez faire est de continuer à transmettre ce SampleRate, inhérent à l’audio spécifique de AudioSampleBuffer, partout. J'ai vu du code dans lequel une constante 44100.0f était transmise à une fonction, car le programmeur ne semblait pas savoir quoi faire d'autre.
C'est un exemple d'échec à assumer sa seule responsabilité.
la source
Une solution concrète peut être élaborée à partir de ce que vous avez dit: une cohésion élevée est une responsabilité qui permet de mesurer la cohésion. Une classe de cohésion maximale contient tous les champs utilisés dans toutes les méthodes. Bien qu'une classe de cohésion maximale ne soit pas toujours possible ni souhaitable, il est toujours préférable de l'atteindre. Avec cet objectif de conception de classe, il est assez facile de déduire que votre classe ne peut pas avoir plusieurs méthodes ou champs (certains disent au plus 7).
Une autre méthode consiste à utiliser les bases pures de la programmation orientée objet: modéliser des objets réels. C'est beaucoup plus facile de voir la responsabilité des objets réels. Cependant, si l'objet réel est trop complexe, divisez-le en plusieurs objets contenant chacun sa propre responsabilité.
la source