GRASP — General Responsibility Assignment Software Patterns — est un ensemble de neuf principes introduits par Craig Larman dans « Applying UML and Patterns » (1997). Alors que SOLID vous indique comment structurer les relations de classes individuelles, GRASP répond à une question plus fondamentale à laquelle chaque développeur est confronté au moment de la conception : quel objet doit être responsable de ce comportement ? GRASP fournit des heuristiques nommées pour répondre à cette question systématiquement plutôt que par intuition. Les modèles ne sont pas des algorithmes : ce sont des lentilles qui rendent le processus de raisonnement explicite et communicable.
Information Expert est le modèle GRASP le plus fréquemment appliqué et la source de la question de conception la plus courante : « Où dois-je placer cette méthode ? La réponse : dans la classe qui contient les données dont la méthode a besoin. Si le calcul du total d’une commande nécessite de connaître les éléments de campagne, la classe Order (qui contient les éléments) doit calculer son propre total – et non un service externe qui accède à l’intérieur de Order pour extraire les articles.
Le modèle Controller répond : qui doit gérer un événement système (une action utilisateur, un message entrant, un déclencheur planifié) ? Pas les objets de domaine – ils devraient ignorer les mécanismes de livraison. Pas l’interface utilisateur – elle doit ignorer la logique métier. Le Controller est une classe non-UI qui reçoit des événements et délègue aux objets de domaine. Il coordonne mais ne calcule pas. En pratique : un contrôleur REST est un contrôleur GRASP. Il en va de même pour un consommateur de messages, un gestionnaire de commandes CLI ou un planificateur de travaux par lots : tous sont des contrôleurs pour différents mécanismes de livraison.
Le modèle de polymorphisme aborde la variation comportementale basée sur le type. Lorsque vous voyez un commutateur ou if/else sur un champ de type, cela indique généralement que le modèle de polymorphisme s'applique : chaque branche du conditionnel doit être un sous-type et le comportement doit être distribué par le système de types - et non par l'appelant. Ceci est directement lié à OCP : le commutateur grandit avec chaque nouveau type ; le polymorphisme signifie que l'ajout d'un nouveau type ajoute une nouvelle classe sans toucher au code existant.
Larman a qualifié les variations protégées de « principe le plus fondamental dans la conception de logiciels » – et il est difficile de prétendre le contraire. Chaque modèle de conception, chaque style architectural, chaque abstraction existe pour protéger le code stable des changements volatils. L'application pratique : identifiez les points d'instabilité de votre système (API externes, règles métier qui changent fréquemment, technologie de base de données, bibliothèques tierces) et enveloppez chacun dans une interface stable. Le code qui dépend de l'interface est protégé — il ne changera pas lorsque l'instabilité changera.
Pure Fabrication résout la tension entre une cohésion élevée et la nécessité de placer les problèmes d’infrastructure quelque part. Pensez à la persistance : l’entité Order ne doit pas savoir comment se sauvegarder dans une base de données – cela violerait le SRP et introduirait une infrastructure dans le domaine. Mais la logique de la persistance doit vivre quelque part. Un référentiel est une pure fabrication : une classe inventée à des fins de conception qui n'a pas d'équivalent direct dans le domaine du problème. Il existe pour donner au comportement de persistance un foyer à haute cohésion et à faible couplage. Autres exemples : Mapper, Logger, EventPublisher, CacheManager. Tous sont de pures fabrications – inventées pour la conception, pas pour le domaine.