Accueil / Tutoriels / Chain of responsibility
Chain of responsibility
Publié le 3 Mars 2025Chain 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
Exemples d’utilisations
Les requêtes HTTP
Validation des formulaires
Points d’attentions
Implémenter une chaîne de responsabilité
Exemple d'utilisation de Chain of responsibility en Go
package data
type SignUpRequest struct {
Username string
Email string
Password string
}
package handler
import (
"fmt"
)
type Handler interface {
SetNext(handler Handler)
Handle(request *data.SignUpRequest)
}
type BaseHandler struct {
next Handler
}
func (h *BaseHandler) SetNext(handler Handler) {
h.next = handler
}
func (h *BaseHandler) HandleNext(request *data.SignUpRequest) {
if h.next != nil {
h.next.Handle(request)
} else {
fmt.Println("Fin de la chaîne de handlers")
// Définir ici un traitement pour la fin de la chaîne
}
}
package handler
import (
"fmt"
"slices"
)
type CheckDuplicateEmailHandler struct {
BaseHandler
// On simule une base d'utilisateurs existants.
existingUsers [ ]string
}
func (h *CheckDuplicateEmailHandler) Handle(request *data.SignUpRequest) {
// Utilisateurs existants.
h.existingUsers = [ ]string{"pierre@mail.com", "paul@mail.com", "jack@mail.com"}
if slices.Contains(h.existingUsers, request.Email) {
// Gérer le cas où l'email existe déjà
fmt.Println("Erreur lors de l'inscripion...")
return
}
h.HandleNext(request)
}
// SendEmailHandler simule l'envoi d'un email de bienvenue.
type SendEmailHandler struct {
BaseHandler
}
func (h *SendEmailHandler) Handle(request *data.SignUpRequest) {
// Simulation de l'envoi d'un email
fmt.Printf("Confirmation d'inscription envoyé à %s\n", request.Email)
h.HandleNext(request)
}
package handler
import (
"fmt"
)
type PasswordValidityHandler struct {
BaseHandler
}
// Exemple pour vérifier la validité d'un mot de passe
func (h *PasswordValidityHandler) Handle(request *data.SignUpRequest) {
if len(request.Password) < 6 {
fmt.Println("Mot de passe trop court !")
return
}
h.HandleNext(request)
}
package main
import (
"fmt"
"training.go/designpatterns/chain-of-responsibility/data"
"training.go/designpatterns/chain-of-responsibility/handler"
)
func main() {
emailChecker := &handler.CheckDuplicateEmailHandler{}
passwordChecker := &handler.PasswordValidityHandler{}
emailSender := &handler.SendEmailHandler{}
// Mise en place d'une chaîne de responsabilité
// emailChecker -> passwordChecker -> emailSender
emailChecker.SetNext(passwordChecker)
passwordChecker.SetNext(emailSender)
// Cas 1 : Inscription OK
signUp1 := &data.SignUpRequest{
Username: "Robert",
Email: "robert@mail.com",
Password: "tototiti",
}
fmt.Println("******* Cas 1 *******")
emailChecker.Handle(signUp1)
// ******* Cas 1 *******
// Confirmation d'inscription envoyé à robert@mail.com
// Fin de la chaîne de handlers
// Cas 2 : Mot de passe trop court
signUp2 := &data.SignUpRequest{
Username: "Manon",
Email: "manon@mail.com",
Password: "123",
}
fmt.Println("******* Cas 2 *******")
emailChecker.Handle(signUp2)
// ******* Cas 2 *******
// Mot de passe trop court !
// Cas 3 : Mail non valide
signUp3 := &data.SignUpRequest{
Username: "Pierre",
Email: "pierre@mail.com",
Password: "123456789",
}
fmt.Println("******* Cas 3 *******")
emailChecker.Handle(signUp3)
// ******* Cas 3 *******
// Erreur lors de l'inscription...
}
Le même exemple en PHP
namespace Practice\DesignPatterns\ChainOfResponsibility;
interface HandlerInterface
{
public function setNext(HandlerInterface $handler): HandlerInterface;
public function handle(SignUpRequest $request): void;
}
namespace Practice\DesignPatterns\ChainOfResponsibility;
abstract class BaseHandler implements HandlerInterface
{
protected ?HandlerInterface $nextHandler = null;
public function setNext(HandlerInterface $handler): HandlerInterface
{
$this->nextHandler = $handler;
return $handler;
}
public function handle(SignUpRequest $request): void
{
if ($this->nextHandler !== null) {
$this->nextHandler->handle($request);
} else {
echo "Processus d'inscription terminé avec succès.
";
}
}
}
namespace Practice\DesignPatterns\ChainOfResponsibility;
class SignUpRequest
{
public string $username;
public string $email;
public string $password;
public function __construct($username, $email, $password)
{
$this->username = $username;
$this->email = $email;
$this->password = $password;
}
}
namespace Practice\DesignPatterns\ChainOfResponsibility;
class CheckDuplicateEmailHandler extends BaseHandler
{
private array $emails = ["pierre@mail.com", "paul@mail.com", "jack@mail.com"];
public function handle(SignUpRequest $request): void
{
if (in_array($request->email, $this->emails)) {
// Gérer le cas où l'email existe déjà
echo "Erreur lors de l'inscripion...
";
// Gérer l'erreur
return;
}
parent::handle($request);
}
}
namespace Practice\DesignPatterns\ChainOfResponsibility;
class CheckPasswordHandler extends BaseHandler
{
public function handle(SignUpRequest $request): void
{
if (strlen($request->password) < 6) {
// Gérer le cas où le mot de passe n'est pas au bon format
echo "Mots de passe trop court !
";
// Gérer l'erreur
return;
}
parent::handle($request);
}
}
namespace Practice\DesignPatterns\ChainOfResponsibility;
class SendEmailHandler extends BaseHandler
{
public function handle(SignUpRequest $request): void
{
echo "Confirmation d'inscription envoyé à " . $request->email . "
";
parent::handle($request);
}
}
use Practice\DesignPatterns\ChainOfResponsibility\CheckDuplicateEmailHandler;
use Practice\DesignPatterns\ChainOfResponsibility\CheckPasswordHandler;
use Practice\DesignPatterns\ChainOfResponsibility\SendEmailHandler;
use Practice\DesignPatterns\ChainOfResponsibility\SignUpRequest;
$emailChecker = new CheckDuplicateEmailHandler();
$passwordChecker = new CheckPasswordHandler();
$emailSender = new SendEmailHandler();
$emailChecker->setNext($passwordChecker);
$passwordChecker->setNext($emailSender);
echo "CAS 1
";
$signUpRequest = new SignUpRequest("Robert", "robert@mail.com", "tototiti");
$emailChecker->handle($signUpRequest);
echo "CAS 2
";
$signUpRequest2 = new SignUpRequest("Manon", "manon@mail.com", "123");
$emailChecker->handle($signUpRequest2);
echo "CAS 3
";
$signUpRequest3 = new SignUpRequest("Pierre", "pierre@mail.com", "123456789");
$emailChecker->handle($signUpRequest3);