Modèle anémique et riche dans le contexte des modèles GRASP

Dans un récent numéro du podcast DotNet & More, nous avons discuté avec Maxim Arshinov de son prochain rapport sur le Moscou .Suivant "L'éclat et la pauvreté du modèle sujet". La position de Maxim sera facilement accessible directement lors de la conférence. Et, en plus, je voudrais considérer la vision du grand débat Anemic VS "Rich" ("Rich") domain models à travers le prisme des modèles GRASP autrefois populaires


Les discussions se poursuivent depuis longtemps, par exemple:



Avant de commencer l'analyse, je voudrais clarifier l'objet du différend. La principale différence entre le modèle anémique et le modèle riche est qu'il ne contient pas de logique commerciale dans le corps de la classe. Un exemple bien connu du modèle anémique peut être le schéma DTO bien connu.


Un modèle «riche», à son tour, peut contenir une logique qui décrit les règles métier, les fonctions , etc. Veuillez noter que nous étudions les méthodes qui reflètent la logique métier. ToString, GetHashCode et d'autres parties "techniques" des classes ne sont pas inclus dans le sujet de discussion et sont donc ignorés.


GRASP


Comme indiqué au début de l'article, nous examinerons cette question dans le contexte des modèles GRASP . Cet ensemble de modèles a été présenté dans le livre de Craig Larman «The Use of UML and Design Patterns» et a grandement influencé la programmation moderne, par exemple, les règles Low Coupling / High Cohesion ont été annoncées dans GRASP.


Pour les personnes familiarisées avec les modèles GoF, cet ensemble de modèles peut sembler trop flou. Le fait est que les modèles GRASP ne se concentrent pas sur la résolution de problèmes appliqués, mais sur la répartition des responsabilités pour certaines actions et opérations entre les objets:


  • Le créateur est responsable de la création d'objets.
  • Le contrôleur est responsable des opérations des utilisateurs
  • L'indirection est responsable de l'organisation du maillage faible entre les objets.
    Et ainsi de suite.

Dans le contexte de cet article, je voudrais me concentrer sur les modèles suivants:


  • Expert en information
  • Fabrication pure

Expert en information


Problème: Quel est le principe de base du partage des responsabilités entre les établissements?
Solution: Attribuez cette tâche à une classe qui dispose de suffisamment d'informations pour l'exécuter.


En d'autres termes:


La responsabilité devrait être attribuée à celui qui possède le maximum d'informations nécessaires à l'exécution - l'expert en information.

Dans le contexte de C # : une méthode doit être déclarée dans la classe dont les champs et les propriétés sont utilisés dans cette méthode.
Par exemple, si pour calculer le montant de la dette, toutes les informations nécessaires sont dans l'essence du débiteur (montant, moment de l'octroi du prêt), c'est dans cette essence que la méthode appropriée doit être annoncée.
Bien sûr, cette simplification est quelque peu excessive, mais le point principal doit être clair.


Fabrication pure


Problème: quelle classe doit fournir l'implémentation de haute cohésion et faible couplage si le modèle Information Expert ne fournit pas de solution appropriée.
Solution: Attribuez un groupe de tâches avec un haut degré d'engagement à une classe artificielle qui ne représente pas un concept spécifique du domaine.


En d'autres termes:


S'il n'est pas possible de sélectionner sans équivoque l'entité appropriée du modèle sujet, à laquelle la responsabilité pourrait être attribuée, il est nécessaire de créer une classe synthétique qui n'existe pas dans le domaine sujet.

Dans le contexte de C # : si l'implémentation de la méthode prévoit l'utilisation uniforme de plusieurs entités ou dépendances externes, alors cette méthode doit être déclarée dans une classe distincte. Et ces classes sont appelées services.
Par exemple, si pour calculer le montant de la dette, vous devez connaître non seulement les attributs du débiteur, mais également les paramètres de la banque (taux d'intérêt, période de délai admissible), alors il vaut la peine de créer un service distinct contenant la méthode appropriée.


Et qu'est-ce que tout cela signifie?


Dans le cadre de ce qui précède, on peut distinguer un algorithme assez simple qui aide à prendre une décision, à placer la méthode dans un modèle ou dans un service :


  • Si une méthode utilise uniquement les propriétés du modèle, elle doit être déclarée dans le modèle
  • Si une méthode utilise, pour la plupart, les propriétés d'un modèle et seulement partiellement un autre, elle peut être déclarée dans le modèle
  • Si la méthode utilise uniformément les propriétés de plusieurs modèles, il vaut la peine de la déplacer vers un service distinct ou existant
  • Si une méthode utilise une dépendance externe, par exemple un référentiel, elle doit être déplacée vers un service distinct ou existant


Résumé


Les modèles GRASP ne peuvent pas être considérés comme la vérité ultime. Mais ils peuvent aider à comprendre facilement à quel objet attribuer tel ou tel comportement. En conséquence, le différend est anémique ou le modèle «riche» peut ne pas avoir de sens, puisque la décision est prise dans chaque cas, en fonction du modèle du sujet et du comportement qui lui est associé. Dans le processus de conception du système, les deux entités avec et sans comportement apparaîtront. Et c'est tout à fait correct.

Source: https://habr.com/ru/post/fr470021/


All Articles