it-swarm-fr.com

Clarifier le principe de responsabilité unique

Le principe de responsabilité unique indique qu'une classe devrait faire une seule et une seule chose. Certains cas sont assez clairs. D'autres, cependant, sont difficiles, car ce qui ressemble à une "une chose" lorsqu'il est vu à un niveau d'abstraction donné peut être plusieurs choses lors de la visualisation à un niveau inférieur. Je crains également que si le principe de responsabilité unique est honoré aux niveaux inférieurs, de manière excessivement découplée, code Verbose Ravioli, où davantage de lignes sont consacrées à la création de classes minuscules pour tout et des informations sur la plomberie autour de la résolution du problème, peut en résulter.

Comment décririez-vous quelle "une chose" signifie? Quels sont certains signes concrets qu'un cours fait vraiment plus qu'une "une chose"?

71
dsimcha

J'aime vraiment la façon dont Robert C. Martin (oncle Bob) Restate le principe de responsabilité unique (lié au PDF) :

Il ne devrait jamais y avoir plus d'une raison pour changer une classe

Il est subtilement différent de la définition traditionnelle "devrait faire une seule chose", et j'aime ça parce que cela vous oblige à changer votre façon de penser de votre classe. Au lieu de penser à "Est-ce que cela fait une chose?", Pensez-vous plutôt à ce qui peut changer et comment ces changements affectent votre classe. Donc, par exemple, si la base de données change votre classe doit-elle changer? Qu'en est-il si le périphérique de sortie change (par exemple un écran ou un périphérique mobile ou une imprimante)? Si votre classe doit changer en raison de changements de nombreuses autres directions, c'est un signe que votre classe a trop de responsabilités.

Dans l'article lié, oncle Bob conclut:

Le SRP est l'un des principes les plus simples et l'un des plus difficiles à obtenir. Les responsabilités de la conjointement sont quelque chose que nous faisons naturellement. Trouver et séparer ces responsabilités les uns des autres est une grande partie de la conception du logiciel.

57
Paddyslacker

Je continue à me demander quel problème est SRP essaye de résoudre? Quand SRP m'a aida-t-il? Voici ce que j'ai proposé:

Vous devez refactoriser la responsabilité/la fonctionnalité d'une classe lorsque :

1) Vous avez dupliqué la fonctionnalité (sec)

2) Vous constatez que votre code a besoin d'un autre niveau d'abstraction afin de vous aider à le comprendre (baiser)

3) Vous constatez que les pièces de fonctionnalité sont comprises par vos experts de domaine comme étant distincts d'un composant différent (langage omniprésent)

Vous ne devriez pas refroidir la responsabilité d'une classe lorsque :

1) Il n'y a aucune fonctionnalité dupliquée.

2) La fonctionnalité n'a pas de sens en dehors du contexte de votre classe. Mettez un autre moyen, votre classe fournit un contexte dans lequel il est plus facile de comprendre la fonctionnalité.

3) Vos experts de domaine n'ont pas de concept de cette responsabilité.

Il me semble que si SRP est appliqué à largement, nous échangeons un type de complexité (essayant de faire des têtes ou des queues d'une classe avec beaucoup trop à l'intérieur) avec un autre type (essayant de garder tous les collaborateurs/niveaux de abstraction droite afin de déterminer ce que ces classes font réellement).

En cas de doute, laissez-le sortir! Vous pouvez toujours refroidir plus tard, quand il y a un cas clair pour cela.

Qu'est-ce que tu penses?

18
Brandon

Je ne sais pas s'il y a une échelle objective à cela, mais ce qui donnerait à cela serait les méthodes - pas tant le nombre d'entre eux, mais la variété de leur fonction. Je suis d'accord que vous pouvez prendre la décomposition trop loin mais je ne suivrais aucune règle difficile et rapide à ce sujet.

4
Jeremy

La réponse réside dans la définition

Ce que vous définissez la responsabilité d'être, vous donne finalement la frontière.

Exemple :

J'ai une composante qui a la responsabilité de affichant factures -> Dans ce cas, si je commençais à ajouter quelque chose de plus, je brise le principe.

Si d'autre part si j'ai dit la responsabilité de -manipulation Factures -> Ajout de plusieurs fonctions plus petites (par exemple, l'impression -facture, mise à jour facture) Tous sont dans cette limite.

Toutefois, si ce module a commencé à manipuler n'importe quelle fonctionnalité en dehors de -factures, il serait alors en dehors de cette limite.

3
Darknight

Je le considère toujours sur deux niveaux:

  • Je m'assure que mes méthodes seulement font une seule chose et le faire bien
  • Je vois une classe comme un regroupement logique (OO) de ces méthodes qui représente une chose bien

Alors quelque chose comme un objet de domaine appelé chien:

Dog est ma classe mais les chiens peuvent faire beaucoup de choses! Je pourrais avoir des méthodes telles que walk(), run() et bite(DotNetDeveloper spawnOfBill) (désolé ne pouvait pas résister; p).

Si Dog devient à manifester alors je penserais à la manière dont les groupes de ces méthodes peuvent être modélisés ensemble dans une autre classe, telle qu'une classe Movement, qui pourrait contenir mon walk() et run() méthodes.

Il n'y a pas de règle dure et rapide, votre conception OO va évoluer au fil du temps. J'essaie d'aller pour une interface transparente/une API publique ainsi que des méthodes simples qui font une chose et une chose bien.

2
Martijn Verburg

Une classe devrait faire une chose lors de la visualisée à son propre niveau d'abstraction. Cela fera sans doute beaucoup de choses à un niveau moins abstrait. C'est ainsi que les classes fonctionnent pour rendre les programmes plus maintenus: ils cachent les détails de la mise en œuvre si vous n'avez pas besoin de les examiner de près.

J'utilise des noms de classe comme un test pour cela. Si je ne peux pas donner à une classe un nom descriptif assez court, ou si ce nom a un mot comme "et" dedans, je violais probablement le principe de responsabilité unique.

D'après mon expérience, il est plus facile de conserver ce principe aux niveaux inférieurs, où les choses sont plus concrètes.

1
David Thornley

Je le regarde plus dans les lignes d'une classe devrait seulement représenter une chose. Pour approprié @ Karianna's Exemple, j'ai mon Dog classe, qui contient des méthodes pour walk(), run() et bark(). Je ne vais pas ajouter de méthodes pour meaow(), squeak(), slither() ou fly() Parce que ce ne sont pas des choses que les chiens ne font pas. Ce sont des choses que les autres animaux font, et ces autres animaux auraient leurs propres cours pour les représenter.

(BTW, si votre chien fait voler, vous devriez probablement arrêter de le jeter hors de la fenêtre).

1
JohnL

Quelque chose à garder à l'esprit: SRP, appliqué correctement, est utile. D'autre part, SRP, mal interprété mal, est une recette de désastre total (un poste ici récemment: "Nous avons commencé à utiliser SRP. Nous sommes passés de 70 classes à 700. Est-ce normal?").

Donc, si vous vous trouvez vous-même dans une situation où vous pensez que SRP veut que vous fassiez quelque chose de stupide, alors arrêtez-vous et réfléchissez à la manière dont vous pourriez avoir mal interprété SRP.

1
gnasher729

Comment décririez-vous quelle "une chose" signifie? Quels sont certains signes concrets qu'un cours fait vraiment plus qu'une "une chose"?

Si une classe a des choses (méthodes ou champs) qui ne se réfèrent pas les uns les autres, il fait plus qu'une "une chose". C'est ce que cohésion signifie et quel SRP a essayé de reposer/réutiliser.

Le point est plus subtil, bien sûr, et il a (comme tout) les zones grises, mais de manière plus utilisable que toutes les définitions de SRP jusqu'à présent.

0
Robert Bräutigam

Il s'agit d'avoir une unique Rôle.

Chaque classe doit être reprise par un nom de rôle. Un rôle est en fait un (ensemble de) verbe (s) associé (s) associé (s) dans un contexte.

Par exemple :

Fichier fournissez l'accès d'un fichier. FileManager Gérer les objets de fichier.

Ressources contiennent des données pour une ressource d'un fichier. ResourceManager détient et fournit toutes les ressources.

Ici, vous pouvez voir que certains verbes comme "Gérer" impliquent un ensemble d'autres verbes. Les verbes seuls sont mieux pensés comme des fonctions que les classes, la plupart du temps. Si le verbe implique trop d'actions qui ont leur propre contexte commun, il devrait s'agir d'une classe en soi.

Ainsi, l'idée n'est que de vous laisser une idée simple de ce que la classe en définissant un rôle unique, qui pourrait être l'accusation de plusieurs sous-groupes (exécutés par des objets membres ou d'autres objets).

Je construis souvent des cours de gestionnaire qui ont plusieurs autres classes différentes. Comme une usine, un registre, etc. Voir une classe de gestionnaire comme une sorte de chef de groupe, un chef d'orchestre qui guident les autres peuples à travailler ensemble pour atteindre une idée de haut niveau. Il a un seul rôle, mais implique de travailler avec d'autres rôles uniques à l'intérieur. Vous pouvez également le voir comme comment une entreprise est organisée: un PDG n'est pas productif sur le niveau de productivité pure, mais s'il n'est pas là, rien ne peut fonctionner correctement ensemble. C'est son rôle.

Lorsque vous concevez, identifiez des rôles uniques. Et pour chaque rôle, voir à nouveau s'il ne peut pas être coupé dans plusieurs autres rôles. De cette façon, si vous avez besoin de simuler la manière dont votre responsable construit des objets, changez simplement l'usine et allez-y en pensant.

0
Klaim