|
JAVA
DESIGN PATTERNS
Behavioral
Patterns - Chain of Responsibility Pattern
The
chain of responsibility pattern is based on
the same principle as written above. It decouples
the sender of the request to the receiver. The
only link between sender and the receiver is
the request which is sent. Based on the request
data sent, the receiver is picked. This is called
“data-driven”. In most of the behavioral patterns,
the data-driven concepts are used to have a
loose coupling.
The responsibility of handling the request data
is given to any of the members of the “chain”.
If the first link of the chain cannot handle
the responsibility, it passes the request data
to the next level in the chain, i.e. to the
next link. For readers, familiar with concepts
of Java, this is similar to what happens in
an Exception Hierarchy. Suppose the code written
throws an ArrayIndexOutOfBoundsException. Now,
this exception is because of some bug in coding
and so, it gets caught at the correct level.
Suppose, we have an application specific exception
in the catch block. This will not be caught
by that. It will find for an Exception class
and will be caught by that as both the application
specific exceptions and the ArrayIndexOutOfBoundsException
are sub-classes of the class Exception.
Once get caught by the exception, which is the
base class, it will then not look for any other
exception. This is precisely the reason why,
we get an “Exception is unreachable” message
when we try to add a catch block with the exception
below the parent exception catch block.
So, in short, the request rises in hierarchy
till some object takes responsibility to handle
this request.
It’s the same mechanism used for multi-level
filtration. Suppose, we have a multi level filter
and gravel of different sizes and shapes. We
need to filter this gravel of different sizes
to approx size categories. We will put the gravel
on the multi-level filtration unit, with the
filter of maximum size at the top and then the
sizes descending. The gravel with the maximum
sizes will stay on the first one and rest will
pass, again this cycle will repeat until, the
finest of the gravel is filtered and is collected
in the sill below the filters. Each of the filters
will have the sizes of gravel which cannot pass
through it. And hence, we will have approx similar
sizes of gravels grouped.
Let’s apply the same example in the form of
code.
First, let’s talk about the request data. In
this case, it is the gravel. We call it Matter.
It has size and quantity. Now, the size determines
whether it matches the size of filter or not
and the quantity tells how much matter is below
the size.
Matter.java
package
bahavioral.chainofresponsibility;
public class Matter { |
|
// size of matter
private int size;
// quantity
private int quantity;
/**
* returns the size
*/
public int getSize() {
return size;
}
/**
* sets the size
*/
public void setSize(int size) {
this.size = size;
}
/**
* returns the quantity
*/
public int getQuantity() {
return quantity;
}
/**
* sets the quantity
*/
public void setQuantity(int quantity)
{
this.quantity = quantity;
}
|
}//
End of class |
The
next thing is now the base class. This base
class in our case is Sill. Nothing escapes the
Sill. All the matter is collected in the sill.
Everything which cannot be filtered gets collected
in the Sill. Like all the requests which cannot
be handled at a lower level rise to higher level
and are handled at the highest level.
Sill.java
package
bahavioral.chainofresponsibility;
/**
* Sill.java
*
* This is the base class, you can say,
which collects everything
* and nothing passes this. Whatever matter
is remaining, and is
* still not filtered, is collected here.
*/
public class Sill {
|
|
/**
* Method collect.
* Everything is collected here.
*/
public void collect(Matter gravel) {
} |
}//
End of class |
And
of course, the next class will be the chain. In
the example, I have just created one single class
called Filter1. This class extends from the Sill.
And the chain grows on. Every class like Filter2,
Filter3 etc extends from Filter1, Filter2 and
so on.
Filter1.java
package
bahavioral.chainofresponsibility;
/**
* This is a filter. This filters out the
gravel and
* passes the rest to the next level.
*/
public class Filter1 extends Sill {
|
|
private int size;
public Filter1(int size) {
this.size = size;
}
/**
* over-ridden method from base class
*/
public void collect(Matter gravel) { |
|
|
// for the entire quantity of matter
for(int i = 0; i < gravel.getQuantity();
i++) { |
|
|
|
//
if gravel size is less than size of filter,
// the gravel will pass to the next level. |
|
|
|
|
if(gravel.getSize()
< size) {
super.collect(gravel);
} else {
//collect here. that means, only matter
with less
// size will pass...
} |
|
|
} |
|
|
|
} |
|
|
|
}//
End of class |
This
is how, this pattern works. Based on principles
of decoupling, the pattern is totally data-driven.
The famous example is the Exception hierarchy.
The other advantage is distribution of responsibilities.
There can be such a scenario when none of the
objects in the chain can handle the request.
In this case, the chain will discard the request.
The basic object can also be an interface depending
on needs.
|
|