Patrons de conception/Chaîne de responsabilité
Le patron de conception Chaîne de responsabilité permet à un nombre quelconque de classes d'essayer de répondre à une requête sans connaître les possibilités des autres classes sur cette requête. Cela permet de diminuer le couplage entre objets. Le seul lien commun entre ces objets étant cette requête qui passe d'un objet à l'autre jusqu'à ce que l'un des objets puisse répondre.
Patron de conception | |
---|---|
Catégorie : « Gang of Four » – Comportement | |
Nom français : | Chaîne de responsabilité |
Nom anglais : | Chain-of-responsibility |
Permettre à un nombre quelconque de classes d'essayer de répondre à une requête sans connaître les possibilités des autres classes sur cette requête. |
Utilisation
modifierDès lors qu'une information doit recevoir plusieurs traitements, ou juste être transmise entre différents objets.
Variante
modifierUne variante de ce patron de conception est un arbre de responsabilité, où chaque nœud de traitement transmet l'objet non plus à un seul autre nœud mais à plusieurs nœuds (exemple : un interpréteur de document XML).
Exemples
modifierL'exemple ci-dessous présente un système de journalisation (log en anglais). Lors de la réception d'un message, ce dernier va passer d'un Logger à l'autre, déclenchant ou non le traitement associé.
#include <iostream>
#include <string>
using namespace std;
class Logger
{
protected:
int level;
Logger* next;
public:
enum
{
ERR,
NOTICE,
DEBUG
};
Logger* setNext(Logger* next)
{
this->next = next;
return (this->next);
}
void message(string msg, int priority)
{
if (priority <= this->level)
this->writeMessage(msg);
if (this->next != NULL)
this->next->message(msg, priority);
}
virtual void writeMessage(string msg) = 0;
};
class DebugLogger : public Logger
{
public:
DebugLogger(int level)
{
this->level = level;
this->next = NULL;
}
void writeMessage(string msg)
{
cout << "Message de debug : " << msg << endl;
}
};
class EmailLogger : public Logger
{
public:
EmailLogger(int level)
{
this->level = level;
this->next = NULL;
}
void writeMessage(string msg)
{
cout << "Notification par email : " << msg << endl;
}
};
class ErrorLogger : public Logger
{
public:
ErrorLogger(int level)
{
this->level = level;
this->next = NULL;
}
void writeMessage(string msg)
{
cerr << "Erreur : " << msg << endl;
}
};
int main()
{
// Construction de la chaîne de responsabilité
DebugLogger logger(Logger::DEBUG);
EmailLogger logger2(Logger::NOTICE);
ErrorLogger logger3(Logger::ERR);
logger.setNext(&logger2);
logger2.setNext(&logger3);
logger.message("Entering function y.", Logger::DEBUG); // Utilisé par DebugLogger
logger.message("Step1 completed.", Logger::NOTICE); // Utilisé par DebugLogger et EmailLogger
logger.message("An error has occurred.", Logger::ERR); // Utilisé par les trois Loggers
return 0;
}
Le même exemple que le précédent, en Java.
import java.util.*;
/**
Classe de gestion de journalisation abstraite.
*/
abstract class Logger
{
public static final int
ERR = 0,
NOTICE = 1,
DEBUG = 2;
protected int level;
/** L'élément suivant dans la chaîne de responsabilité. */
protected Logger next;
protected Logger(int level)
{
this.level = level;
this.next = null;
}
public Logger setNext( Logger l)
{
next = l;
return l;
}
public void message( String msg, int priority )
{
if ( priority <= level )
writeMessage( msg );
if ( next != null )
next.message( msg, priority );
}
abstract protected void writeMessage( String msg );
}
/**
Journalisation sur la sortie standard.
*/
class StdoutLogger extends Logger
{
public StdoutLogger( int level ) { super(level); }
protected void writeMessage( String msg )
{
System.out.println( "Writing to stdout: " + msg );
}
}
/**
Journalisation par courriel.
*/
class EmailLogger extends Logger
{
public EmailLogger( int level ) { super(level); }
protected void writeMessage( String msg )
{
System.out.println( "Sending via email: " + msg );
}
}
/**
Journalisation sur l'erreur standard.
*/
class StderrLogger extends Logger
{
public StderrLogger( int level ) { super(level); }
protected void writeMessage( String msg )
{
System.err.println( "Sending to stderr: " + msg );
}
}
/**
Classe principale de l'application.
*/
public class ChainOfResponsibilityExample
{
public static void main( String[] args )
{
// Construire la chaîne de responsabilité
// StdoutLogger -> EmailLogger -> StderrLogger
Logger l,l1;
l1 = l = new StdoutLogger( Logger.DEBUG );
l1 = l1.setNext(new EmailLogger( Logger.NOTICE ));
l1 = l1.setNext(new StderrLogger( Logger.ERR ));
// Traité par StdoutLogger
l.message( "Entering function y.", Logger.DEBUG );
// Traité par StdoutLogger et EmailLogger
l.message( "Step1 completed.", Logger.NOTICE );
// Traité par les trois loggers
l.message( "An error has occurred.", Logger.ERR );
}
}
Ce programme affiche :
Writing to stdout: Entering function y. Writing to stdout: Step1 completed. Sending via e-mail: Step1 completed. Writing to stdout: An error has occurred. Sending via e-mail: An error has occurred. Writing to stderr: An error has occurred.