Question

La responsabilité unique principe stipule qu'une classe doit faire une et une seule chose. Certains cas sont coupés assez clair. D'autres, cependant, sont difficiles parce que ce qui ressemble à « une chose », vu à un niveau d'abstraction donné peut être plusieurs choses vus à un niveau inférieur. Je crains aussi que si la responsabilité unique principe est honoré aux niveaux inférieurs, trop découplé, le code raviolis verbeux, où plusieurs lignes sont consacrées à la création de petites classes pour tout et l'information de plomberie autour de résoudre effectivement le problème à portée de main, peut entraîner.

Comment décririez-vous ce que « une chose » signifie? Quels sont les signes concrets qu'une classe ne vraiment plus que « une chose »?

Était-ce utile?

La solution

Je aime vraiment la façon dont Robert C. Martin (oncle Bob) la responsabilité unique reformule Principe (lié au format PDF) :

Il ne doit jamais être plus d'une raison pour une classe de changement

Il est subtilement différent de la définition traditionnelle « devrait faire une seule chose », et je l'aime parce qu'il vous oblige à changer la façon dont vous pensez à votre classe. Au lieu de penser « Est-ce faire une chose? », Vous pensez à la place de ce qui peut changer et comment ces changements affecteront-ils votre classe. Ainsi, par exemple, si la base de données des changements que votre besoin de classe pour changer? Qu'en est-il si le dispositif de sortie change (par exemple un écran ou un appareil mobile, ou une imprimante)? Si vos besoins de classe aux changements en raison des changements de beaucoup d'autres directions, puis c'est un signe que votre classe a trop de responsabilités.

Dans l'article lié, l'oncle Bob conclut:

Le SRP est l'un des plus simple des principes, et l'un des plus difficiles à obtenir le droit. Conjoindre responsabilités est quelque chose que nous faisons naturellement. Trouver et séparer les responsabilités les uns des autres est une grande partie de ce que la conception du logiciel est vraiment.

Autres conseils

Je me pose ce problème SRP tente de résoudre? Quand ne me aide SRP? Voici ce que je suis venu avec:

Vous devez factoriser la responsabilité / des fonctionnalités d'une classe lorsque:

1) Vous avez la fonctionnalité dupliquée (SEC)

2) Vous trouvez que votre code a besoin un autre niveau d'abstraction afin de vous aider à comprendre ce (Kiss)

3) Vous trouvez que des morceaux de fonctionnalité sont compris par vos experts du domaine comme étant en dehors d'un composant différent (Ubiquitous Language)

Vous ne devriez pas la responsabilité Refactoriser hors 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. Autrement dit, votre classe offre un contexte dans lequel il est plus facile de comprendre la fonctionnalité.

3) Vos experts de domaine ne sont pas un concept de cette responsabilité.

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

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

Que pensez-vous?

Je ne sais pas s'il y a une échelle objective mais ce qui donnerait à cette distance serait les méthodes - non pas tant le nombre d'entre eux, mais la variété de leur fonction. Je suis d'accord, vous pouvez prendre une décomposition trop loin, mais je ne voudrais pas suivre les règles strictes à ce sujet.

Les mensonges de réponse dans la définition

Ce que vous définir la responsabilité d'être, en fin de compte vous donne la limite.

Exemple:

J'ai un composant qui a la responsabilité de affichage factures -.> Dans ce cas, si je me mettais à ajouter quelque chose de plus je suis briser le principe

Si d'autre part si je disais la responsabilité de Gestion factures -> l'ajout de plusieurs fonctions plus petites (par exemple l'impression Facture , la mise à jour Facture ) tous sont dans cette limite.

Toutefois, si ce module a commencé à poignée tout fonctionnalité en dehors de factures , il serait alors en dehors de cette limite.

Je considère toujours sur deux niveaux:

  • Je fais que mes méthodes ne font qu'une chose et le faire bien
  • Je vois une classe comme logique (OO) le regroupement de ces méthodes qui représentent bien une chose

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 à peu maniable alors je pense à la façon dont les groupes de ces méthodes peuvent être modélisés ensemble dans une autre classe, comme une classe Movement, qui pourrait contenir mes méthodes de walk() et run().

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

Je regarde plus le long des lignes d'une classe ne devrait représentent une chose. S'approprier @ l'exemple de Karianna, j'ai ma classe Dog, qui a des méthodes pour walk(), run() et bark(). Je ne vais pas ajouter des méthodes pour meaow(), squeak(), slither() ou fly() parce que ce ne sont pas des choses que les chiens. Ce sont des choses que les autres animaux, et les autres animaux auraient leurs propres classes pour les représenter.

(BTW, si votre chien Finalité voler, alors vous devriez probablement arrêter de le jeter par la fenêtre).

classe A doit faire une chose quand vu à son niveau d'abstraction. Il sera sans doute faire beaucoup de choses à un niveau moins abstrait. Voici comment les classes travaillent à rendre les programmes plus maintenable. Ils se cachent les détails de mise en œuvre si vous n'avez pas besoin de les examiner de près

J'utilise les 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 » en elle, je ne respecte pas probablement la responsabilité unique principe.

Dans mon expérience, il est plus facile de garder ce principe aux niveaux inférieurs, où les choses sont plus concrètes.

Il est d'avoir un unique, rôle .

doit être repris chaque classe par un nom de rôle. Un rôle est, en fait, un (ensemble de) verbe (s) associé à un contexte.

Par exemple:

Fichier fournissent l'accès d'un fichier. FileManager gérer des objets de fichiers.

données de maintien des ressources pour une ressource à partir d'un fichier. ResourceManager attente et fournir toutes les ressources.

Ici, vous pouvez voir que certains verbes comme « gérer » impliquent un ensemble d'autres verbes. Seuls sont mieux Verbs considérés comme des fonctions que les classes, la plupart du temps. Si le verbe implique trop les actions qui ont leur propre contexte commun, alors il devrait être une classe en soi.

Alors, l'idée est de vous permettre d'avoir une idée simple de ce que fait la classe en définissant un rôle unique, qui pourrait être le agrégat de plusieurs sous-rôle (effectué par des objets membres ou d'autres objets).

Je construis souvent des classes Manager qui ont plusieurs autres classes différentes en elle. Comme une usine, un registre, etc. Voir une classe Manager 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 rôle, mais implique-travailler avec d'autres rôles uniques à l'intérieur. Vous pouvez aussi le voir comme la façon dont une entreprise est organisée: un PDG est pas productif au niveau de la productivité pure, mais s'il n'y est pas, alors rien ne peut fonctionner correctement ensemble. C'est son rôle.

Lorsque vous concevez, identifier les rôles uniques. Et pour chaque rôle, voir à nouveau si elle ne peut être coupé dans plusieurs autres rôles. De cette façon, si vous avez besoin de changer simlpy la façon dont vos objets de construction Manager, il suffit de changer l'usine et aller avec la paix à l'esprit.

Le SRP est non seulement de diviser les classes, mais aussi de déléguer la fonctionnalité.

Dans l'exemple ci-dessus Chien utilisé, ne pas utiliser SRP pour justifier d'avoir 3 classes distinctes, telles que DogBarker, dogwalker, etc (faible cohésion). Au lieu de cela, regardez la mise en œuvre des méthodes d'une classe et de décider si elles « savent trop ». Vous pouvez toujours dog.walk (), mais probablement la méthode de marche () devrait déléguer à une autre classe les détails de la façon dont la marche est accompli.

En effet, nous permettons la classe chien d'avoir une raison de changement: parce que le changement des chiens. Bien sûr, combinant avec d'autres principes SOLIDES vous prolongerions chien de nouvelles fonctionnalités plutôt que de changer de chien (ouvert / fermé). Et vous Injecter vos dépendances telles que IMOVE et IEAT. Et bien sûr vous rendre ces interfaces distinctes (ségrégation d'interface). Chien ne changerait si nous avons trouvé un bug ou si les chiens fondamentalement changé (Liskov Sub, ne se prolongent pas et retirez le comportement).

L'effet net de solide est que nous obtenons d'écrire un nouveau code plus souvent que nous devons modifier le code existant, et qui est une grande victoire.

Tout dépend de la définition de la responsabilité et comment cette définition va à l'entretien de l'impact de votre code. Tout se résume à une chose et qui est la façon dont votre conception va vous aider à maintenir votre code.

Et comme quelqu'un a dit: « Marcher sur l'eau et la conception de logiciels de spécifications données est facile, à condition les deux sont gelés ».

Donc, si nous définissons la responsabilité de façon plus concrète, alors on n'a pas besoin de le changer.

Parfois, les responsabilités sera une évidence aveuglante, mais parfois il peut être subtile et nous devons décider judicieusement.

Supposons, on ajoute une autre responsabilité à la classe Chien nommé catchThief (). Maintenant, il pourrait être conduit vers une autre responsabilité différente. Demain, si la façon dont Dog est voleur attraper doit être changé par département de police, puis la classe Dog devra être changé. Il serait préférable de créer une autre sous-classe dans ce cas et nommez-le ThiefCathcerDog. Mais dans une autre vue, si nous sommes sûrs qu'il ne va pas changer en toute circonstance, ou la façon dont catchThief a été mis en œuvre dépend de certains paramètres externes, il est tout à fait correct d'avoir cette responsabilité. Si les responsabilités ne sont pas que nous avons étonnamment étrange alors décider judicieusement en fonction du cas d'utilisation.

« L'une des raisons de changement » dépend de qui utilise le système. Assurez-vous que vous avez des cas d'utilisation pour chaque acteur, et faire une liste des changements les plus probables, pour chaque changement d'utilisation possible cas sûr qu'une seule classe serait affectée par ce changement. Si vous ajoutez un cas tout à fait nouvelle utilisation, assurez-vous seulement besoin d'étendre une classe de le faire.

Licencié sous: CC-BY-SA avec attribution
scroll top