Chain-of-responsibility pattern
From Wikipedia, the free encyclopedia
In Object Oriented Design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains a set of logic that describes the types of command objects that it can handle, and how to pass off those that it cannot to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain.
In a variation of the standard chain-of-responsibility model, some handlers may act as dispatchers, capable of sending commands out in a variety of directions, forming a tree of responsibility. In some cases, this can occur recursively, with processing objects calling higher-up processing objects with commands that attempt to solve some smaller part of the problem; in this case recursion continues until the command is processed, or the entire tree has been explored. An XML interpreter (parsed, but not yet executed) might be a fitting example.
This pattern promotes the idea of loose coupling, a common programming practice.
Contents |
[edit] Examples
[edit] Java
The following Java code illustrates the pattern with the example of a logging class. Each logging handler decides if any action is to be taken at this log level and then passes the message on to the next logging handler. The output is:
Writing to debug output: Entering function y. Writing to debug output: Step1 completed. Writing to stderr: Step1 completed. Writing to debug output: An error has occurred. Sending via e-mail: An error has occurred. Writing to stderr: An error has occurred.
Note that this example should not be seen as a recommendation to write Logging classes this way.
Also, note that a 'pure' implementation of the CoR would stop further execution of the chain once an object handled the message. In this example an object continues processing the chain whether it tries to handle the command or not.
import java.util.*; abstract class Logger { public static int ERR = 3; public static int NOTICE = 5; public static int DEBUG = 7; protected int mask; protected Logger next; // the next element in the chain of responsibility public Logger setNext(Logger l) { next = l; return this; } abstract public void message(String msg, int priority); } class DebugLogger extends Logger{ public DebugLogger(int mask) { this.mask = mask; } public void message(String msg, int priority) { if (priority <= mask) System.out.println("Writing to debug output: "+msg); if (next != null) next.message(msg, priority); } } class EMailLogger extends Logger{ public EMailLogger(int mask) { this.mask = mask; } public void message(String msg, int priority) { if (priority <= mask) System.out.println("Sending via e-mail: "+msg); if (next != null) next.message(msg, priority); } } class StderrLogger extends Logger{ public StderrLogger(int mask) { this.mask = mask; } public void message(String msg, int priority) { if (priority <= mask) System.out.println("Writing to stderr: "+msg); if (next != null) next.message(msg, priority); } } class ChainOfResponsibilityExample{ public static void main(String[] args) { // building the chain of responsibility Logger l = new DebugLogger(Logger.DEBUG).setNext( new EMailLogger(Logger.ERR).setNext( new StderrLogger(Logger.NOTICE) ) ); l.message("Entering function y.", Logger.DEBUG); // handled by DebugLogger l.message("Step1 completed.", Logger.NOTICE); // handled by Debug- and StderrLogger l.message("An error has occurred.", Logger.ERR); // handled by all three Logger } }
[edit] Visual Prolog
This is an realistic example of protecting the operations on a stream with a named mutex.
First the outputStream interface (a simplified version of the real one):
interface outputStream predicates write : (...). writef : (string FormatString, ...). end interface outputStream
This class encapsulates each of the stream operations the mutex. The finally predicate is used to ensure that the mutex is released no matter how the operation goes (i.e. also in case of excetions). The underlying mutex object is released by a finalizer in the mutex class, and for this example we leave it at that.
class outputStream_protected : outputStream constructors new : (string MutexName, outputStream Stream). end class outputStream_protected #include @"pfc\multiThread\multiThread.ph" implement outputStream_protected facts mutex : mutex. stream : outputStream. clauses new(MutexName, Stream) :- mutex := mutex::createNamed(MutexName, false), % do not take ownership stream := Stream. clauses write(...) :- _ = mutex:wait(), % ignore wait code in this simplified example finally(stream:write(...), mutex:release()). clauses writef(FormatString, ...) :- _ = mutex:wait(), % ignore wait code in this simplified example finally(stream:writef(FormatString, ...), mutex:release()). end implement outputStream_protected
Usage example.
The client uses an outputStream. Instead of receiving the pipeStream directly, it gets the protected version of it.
#include @"pfc\pipe\pipe.ph" goal Stream = pipeStream::openClient("TestPipe"), Protected = outputStream_protected::new("PipeMutex", Stream), client(Protected), Stream:close().
[edit] See also
- Interception pattern
- Interceptor pattern
[edit] External links
- Article "The Chain of Responsibility pattern's pitfalls and improvements" by Michael Xinsheng Huang
- Article "Follow the Chain of Responsibility" by David Geary
- Article "Pattern Summaries: Chain of Responsibility" by Mark Grand
- CoR overview
- Behavioral Patterns - Chain of Responsibility Pattern
- Chain of Responsibility
- Descriptions from Portland Pattern Repository
Creational: Abstract factory • Builder • Factory • Prototype • Singleton
Structural: Adapter • Bridge • Composite • Decorator • Façade • Flyweight • Proxy
Behavorial: Chain of responsibility • Command • Interpreter • Iterator • Mediator • Memento • Observer • State • Strategy • Template method • Visitor