Chain-of-responsibility pattern
Encyclopedia
In Object Oriented Design
Object oriented design
Object-oriented design is the process of planning a system of interacting objects for the purpose of solving a software problem. It is one approach to software design.-Overview:...

, the chain-of-responsibility pattern is a design pattern
Design pattern (computer science)
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that...

 consisting of a source of command objects
Command pattern
In object-oriented programming, the command pattern is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time...

 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 handle 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 dispatcher
Dynamic dispatch
In computer science, dynamic dispatch is the process of mapping a message to a specific sequence of code at runtime. This is done to support the cases where the appropriate method can't be determined at compile-time...

s, 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
Loose coupling
In computing and systems design a loosely coupled system is one where each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. The notion was introduced into organizational studies by Karl Weick...

, which is considered a programming best practice
Best practice
A best practice is a method or technique that has consistently shown results superior to those achieved with other means, and that is used as a benchmark...

.

Example

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 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.

Note that this example should not be seen as a recommendation on how to write logging classes.

Also, note that in a 'pure' implementation of the chain of responsibility pattern, a logger would not pass responsibility further down the chain after handling a message. In this example, a message will be passed down the chain whether it is handled or not.


abstract class Logger {
public static int ERR = 3;
public static int NOTICE = 5;
public static int DEBUG = 7;
protected int mask;

// The next element in the chain of responsibility
protected Logger next;

public Logger setNext(Logger log) {
next = log;
return log;
}

public void message(String msg, int priority) {
if (priority <= mask) {
writeMessage(msg);
}
if (next != null) {
next.message(msg, priority);
}
}

abstract protected void writeMessage(String msg);
}

class StdoutLogger extends Logger {
public StdoutLogger(int mask) {
this.mask = mask;
}

protected void writeMessage(String msg) {
System.out.println("Writing to stdout: " + msg);
}
}
class EmailLogger extends Logger {
public EmailLogger(int mask) {
this.mask = mask;
}

protected void writeMessage(String msg) {
System.out.println("Sending via email: " + msg);
}
}

class StderrLogger extends Logger {
public StderrLogger(int mask) {
this.mask = mask;
}

protected void writeMessage(String msg) {
System.err.println("Sending to stderr: " + msg);
}
}

public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// Build the chain of responsibility
Logger logger, logger1;
logger1 = logger = new StdoutLogger(Logger.DEBUG);
logger1 = logger1.setNext(new EmailLogger(Logger.NOTICE));
logger1 = logger1.setNext(new StderrLogger(Logger.ERR));

// Handled by StdoutLogger
logger.message("Entering function y.", Logger.DEBUG);

// Handled by StdoutLogger and EmailLogger
logger.message("Step1 completed.", Logger.NOTICE);

// Handled by all three loggers
logger.message("An error has occurred.", Logger.ERR);
}
}




Below is another example of this pattern in Java.
In this example we have different roles, each having a fix purchase power limit and a successor. Every time a user in a role receives a purchase request, when it's over his limit, he just passes that request to his successor.

The PurchasePower abstract class with the abstract method processRequest.

abstract class PurchasePower {
protected final double base = 500;
protected PurchasePower successor;

public void setSuccessor(PurchasePower successor) {
this.successor = successor;
}

abstract public void processRequest(PurchaseRequest request);
}



Four implementations of the abstract class above: Manager, Director, Vice President, President


class ManagerPPower extends PurchasePower {
private final double ALLOWABLE = 10 * base;

public void processRequest(PurchaseRequest request) {
if (request.getAmount < ALLOWABLE) {
System.out.println("Manager will approve $" + request.getAmount);
} else if (successor != null) {
successor.processRequest(request);
}
}
}

class DirectorPPower extends PurchasePower {
private final double ALLOWABLE = 20 * base;

public void processRequest(PurchaseRequest request) {
if (request.getAmount < ALLOWABLE) {
System.out.println("Director will approve $" + request.getAmount);
} else if (successor != null) {
successor.processRequest(request);
}
}
}

class VicePresidentPPower extends PurchasePower {
private final double ALLOWABLE = 40 * base;

public void processRequest(PurchaseRequest request) {
if (request.getAmount < ALLOWABLE) {
System.out.println("Vice President will approve $" + request.getAmount);
} else if (successor != null) {
successor.processRequest(request);
}
}
}

class PresidentPPower extends PurchasePower {
private final double ALLOWABLE = 60 * base;

public void processRequest(PurchaseRequest request) {
if (request.getAmount < ALLOWABLE) {
System.out.println("President will approve $" + request.getAmount);
} else {
System.out.println( "Your request for $" + request.getAmount + " needs a board meeting!");
}
}
}



The PurchaseRequest class with its Getter methods which keeps the request data in this example.

class PurchaseRequest {
private int number;
private double amount;
private String purpose;

public PurchaseRequest(int number, double amount, String purpose) {
this.number = number;
this.amount = amount;
this.purpose = purpose;
}

public double getAmount {
return amount;
}
public void setAmount(double amt) {
amount = amt;
}

public String getPurpose {
return purpose;
}
public void setPurpose(String reason) {
purpose = reason;
}

public int getNumber{
return number;
}
public void setNumber(int num) {
number = num;
}
}



And here a usage example, the successors are set like this: Manager -> Director -> Vice President -> President

class CheckAuthority {
public static void main(String[] args) {
ManagerPPower manager = new ManagerPPower;
DirectorPPower director = new DirectorPPower;
VicePresidentPPower vp = new VicePresidentPPower;
PresidentPPower president = new PresidentPPower;
manager.setSuccessor(director);
director.setSuccessor(vp);
vp.setSuccessor(president);

// Press Ctrl+C to end.
try {
while (true) {
System.out.println("Enter the amount to check who should approve your expenditure.");
System.out.print(">");
double d = Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine);
manager.processRequest(new PurchaseRequest(0, d, "General"));
}
} catch(Exception e) {
System.exit(1);
}
}
}

External links

The source of this article is wikipedia, the free encyclopedia.  The text of this article is licensed under the GFDL.
 
x
OK