struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dakota Jack" <dakota.j...@gmail.com>
Subject Re: Reasons for 1.3 release
Date Mon, 20 Feb 2006 17:09:23 GMT
Following is a sample implementation of a real CoR pattern.  Notice how
different it looks?  Notice how data driven it is?



On 2/18/06, Frank W. Zammetti <fzlists@omnytex.com> wrote:
>
> Dakota Jack wrote:
> > The flexibility is clear.  But, from what I can see the pattern is not
> CoR.
>
> Ok, I'll bite... can you explain that?




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


--
"You can lead a horse to water but you cannot make it float on its back."
~Dakota Jack~

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message