Accueil / Tutoriels / Chain of responsibility
Chain of responsibility
Publié le 3 Mars 2025
Chain of responsibility (chaîne de responsabilité en français) est un design pattern comportemental qui permet de faire circuler une requête à travers une chaîne d’objets.
Le principe
La requête et les traitements qui peuvent s’appliquer dessus sont complètement décorrélés. Chaque objet de la chaîne (qu’on appelle par convention des handlers) est indépendant et possède une référence vers le prochain handler de la chaîne. Lorsqu’une requête arrive au niveau d’un handler, le handler à la possibilité d’appliquer un traitement sur la requête, d’ignorer la requête pour la transmettre au handler suivant ou de stopper la transmission.
On se retrouve ainsi avec un code très modulaire et très évolutif. En fonction de nos besoins, on peut ordonner les handlers comme on le souhaite, ajouter ou supprimer des handlers très facilement et avoir un code très adaptable.
Exemples d’utilisations
Les requêtes HTTP
Les middlewares sont un exemple typique d’utilisation de ce pattern. Chaque middleware (handler) va examiner la requête et procéder à une vérification ou un traitement particulier (origine de la requête, méthode utilisé pour la requête (GET, POST, PATCH…), vérifier les autorisations (clé API, JWT, login/mot de passe), procéder à l’écriture dans un fichier de logs.
Validation des formulaires
Lors d’une inscription, vérifier si le format d’une adresse mail est valide par exemple avant de poursuivre le traitement, si un numéro de téléphone est au bon format, etc…
Points d’attentions
Le principe d'une chaîne de responsabilité est de faire passer la requête à travers plusieurs objets. Il existe plusieurs issues possibles pour notre requête. Le débogage peut par conséquent être difficile dans certains cas.
Attention à ne pas mettre trop de handlers dans sa chaîne. Cela peut compliquer la gestion des erreurs et avoir un impact sur la performance.
La modularité que l’on obtient avec les handlers peut aussi devenir un inconvénient majeur. L’ordre d’exécution des handlers peut dans certains cas avoir une importance dans notre programme. Lors d’une mise à jour ou de l’ajout d’un nouveau handler par exemple, il est très facile d’introduire des bugs ou des régressions. Ne pas négliger l’ajout de tests unitaires et fonctionnels !
Implémenter une chaîne de responsabilité
En général pour mettre en place ce pattern, on adopte les conventions suivantes : Créer une interface (ou classe abstraite) nommée handler par exemple. L’interface définit la signature d’une méthode qui renseignera le handler suivant de la chaîne setNext() et la signature d’une méthode dédiée au traitement de la requête handle().
Créer nos handlers qui implémentent notre interface / hérite de la classe abstraite.
Exemple d'utilisation de Chain of responsibility en Go
Voici un exemple en Go pour gérer un formulaire d’inscription.
On représente ici les données d'inscriptions :
Notre interface Handler - Avec les signatures de SetNext() et Handle(). On ajoute une implémentation de base qui servira à tous nos handlers. La méthode Handle() sera directement implémenté au niveau des handlers.
On met en place notre handler pour gérer l'email renseigné dans le formulaire.
Un autre handler pour gérer le mots de passe renseigné.
Notre fichier principal. On initialise nos handlers et on mets en place notre chaîne de responsabilité. J'ai mis quelques exemples pour pour faire intervenir ou non nos handlers.
Le même exemple en PHP
Voici exactement le même exemple mais avec PHP :
index.php
Conclusion
J'espère que grâce à cet article vous êtes désormais plus à l'aise avec le design pattern Chain of responsibility. Vous pouvez retrouver mon article sur les design patterns ou les autres tutoriels sur Observer, Decorator, Iterator et Factory.