Introduction
This is my first CodeProject article and I’m going to explain one important design pattern called Chain of Responsibility pattern.
Background
Before going to explain Chain of Responsibility Pattern, I would like to put few words about Design Pattern. Design Patterns are very beneficial to develop a large scale software solution because you may know a large software solution needs such kind of codes which have easier way of Code Modification, Code Extensibility and those lines of code could be used by other coders which is known as Code Reusability. If you are a very beginner and surprisingly this is the first pattern you are trying to learn then I would suggest you collect the book – “Design Patterns: Elements of Reusable Object-Oriented Software” and have a look of wiki pages of Design Pattern .
Why Chain of Responsibility:
I’m not going to start with formal definition of Chain of Responsibility Pattern. Rather, consider an object which is called request object and this object must be processed by another object(s). More specifically we can say a group of objects each of which is called responsible object will process the request object. One responsible object, however, may process the request object entirely or more than one responsible object may process request partially. There will be a chain of responsible objects, one after another and that is why the name of the pattern is Chain of Responsibility. Take a look on the following figure:
The above figure demonstrates a simple chain of responsible objects. At first request is sent to ResponsibleObject1. Whether or not request is processed by ResponsibleObject1, request will be sent to ResponsibleObject2 by ResponsibleObject1 itself. Thus one request may be processed by several objects. If you wish you can also stop propagation of request from one responsible object to another if the request is already processed entirely.
Well, you may assume there is always a simple straight chain of responsible objects. But that’s not true actually. There may be a tree of responsible objects and propagation of request will follow the tree structure. For example take a look on the following figure:
Now it’s time to uncover the actual intent of Chain of Responsibility. Perhaps you have already understood intent of the pattern. Whatever you understood, first of all let me state what is stated in the book of Gang of Four.
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
Using Chain of Responsibility pattern we are avoiding the assumption that “One request will processed by only one receiver (responsible object)”. This is not practically true and is a very important aspect of this pattern and it’s very advantageous to make a chance to handle a request by more than one object. Isn’t?
Example
Probably I took much time already. So to keep this article short in length now I’m going to narrate a practical example of my own…
Consider, a courier service company has several divisions to handle customer requests properly. For example, one Division may be dedicated to handle customer requests of sending parcels of heavy weight. Another division may have responsibility to handle customer requests with large amount of money. There may have one general division which can send both parcels and money but should be very little amount of money or low weight of parcels. Now let’s map this courier service company with chain of responsibility pattern. Here customer’s order is the request object and each division is a responsible object. One customer’s request, however, will be processed by which division is depends on weight of customer’s parcel or amount of money. If a customer wants to send parcel and money then the customer’s order (request) should be processed both by Parcel Division and Money Division.
For an easy understanding let’s build a tree of responsible Divisions. In the root of the tree there should be GeneralDivision. This division can handle maximum weight of 10 Kilograms and 10000 dollars. ParcelDivisionOne can handle parcels of maximum weight 100 Kilograms. ParcelDivisionTwo can handle parcels of unlimited weight (imaginary) and the MoneyDivision can handle any amount of money. All of those are assumption. Whatever we assumed let’s take a look at the tree of Divisions:
We will go through code segment but before that here is UML Class diagram of Chain of Responsibility Pattern. According to UML Class diagram it’s clear that there are three participants in this pattern and they are Request
, RequestHandler
and obviously there should be <code>Client
.
Code
Let’s go through code segments. First of all we need to produce customer’s order (request object). The following Request
class will produce request objects:
class Request {
private double weight;
private double money;
public Request(double w, double m)
{
this.weight = w;
this.money = m;
}
public double getWeight()
{
return this.weight;
}
public double getMoney()
{
return this.money;
}
}
Now I’m going to make an abstract class named Division
. By extending this abstract class we will make responsible classes and each of those classes represents a particular Division of the courier service company. Let’s see what we have in Division
abstract class.
abstract class Divison {
protected List nextList = new ArrayList();
public void addNextDivison(Divison d)
{
this.nextList.add(d);
}
public void handle(Request request)
{
for(int i=0; i < nextList.size(); i++) {
Divison d = nextList.get(i);
d.handle(request);
}
}
protected abstract void processRequest();
}
nextList
is the list of next responsible objects. Doesn’t it make sense? Well, what will a Division (Responsible Object) do if it is unable to handle customer order (Request)? In such situation it will send orders to the divisions stored in nextList
using the function handle(Request request)
.
processRequest()
is a abstract function which will be defined in concrete classes and this function will contain actual code to handle/process a request.
Now it’s time to define GeneralDivision
, ParcelDivisionOne
, ParcelDivisionTwo
, MoneyDivision
by extending Division
.
class GeneralDivison extends Divison {
@Override
public void handle(Request request)
{
if(request.getWeight() <= 10 && request.getMoney() <= 10000)
processRequest();
else super.handle(request);
}
public void processRequest()
{
System.out.println("This request is processed by -- General Divison");
}
}
class ParcelDivisonOne extends Divison {
@Override
public void handle(Request request)
{
if(request.getWeight() <= 100) processRequest();
else super.handle(request);
}
public void processRequest()
{
System.out.println("This request is processed by -- ParcelDivisonOne");
}
}
class ParcelDivisonTwo extends Divison {
@Override
public void handle(Request request)
{
if(request.getWeight() > 0) processRequest();
}
public void processRequest()
{
System.out.println("This request is processed by -- ParcelDivisonTwo");
}
}
class MoneyDivison extends Divison {
@Override
public void handle(Request request)
{
if(request.getMoney() > 0) processRequest();
}
public void processRequest()
{
System.out.println("This request is processed by -- MoneyDivison");
}
}
Did we relate the responsible Divisions ever? Obviously we need to relate responsible objects whether it could be a chain or tree responsibility. Code in the following is easy to understand which does this relationship among responsible objects and also demonstrates how client will handle request using one responsible object.
public class CourierServiceDemo {
private static Divison createDivison()
{
Divison div1 = new GeneralDivison();
Divison div2 = new ParcelDivisonOne();
Divison div3 = new ParcelDivisonTwo();
Divison div4 = new MoneyDivison();
div2.addNextDivison(div3);
div1.addNextDivison(div2);
div1.addNextDivison(div4);
return div1;
}
public static void main(String[] args)
{
Divison div = createDivison();
div.handle(new Request(101, 10));
}
}
Now it’s your time to change request object data or make new request object and pass them to handle()
function to see what happens.