Wednesday, October 22, 2014

Chain of Responsibility Design Pattern

Raise ticket for IT/HR related issues rather than talking directly to a specific person. Follow process !

Chain of Responsibility (i.e. COR) is a behavioral design pattern which allows an object to send request without knowing who is going to handle the request. The request is sent to a list of receivers or handlers in a chain, where each object can either handle or pass it on to the next. So, it loosely couples sender and receiver (similar to command pattern).

Intent (as put in Gang of four book)
Avoid coupling the sender of a request to its receivers 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.
Pattern abstracts the pool of receivers(analogous to pool of threads), so all receivers need to agree to an (communication) interface i.e. Handler.  All subclass of Handler need to agree to the interface of Handler. If a concrete handler can't process a request, then it passes it down to next handler or successor in the chain.

Handler is an abstract class in example shown below. We could implement Handler as interface as well by making getSuccessor() method also abstract. In this case, implementation will have to be provided by concrete handlers.

Generated with ObjectAid UML - Eclipse plugin


package cor.pattern;

/**
 * Base handler class
 *
 */
public abstract class Handler {
 protected Handler successor;
 
 public Handler getSuccessor() {
  return successor;
 }

 public abstract void handleRequest(Request request);
}

package cor.pattern;

/**
 * first handler
 *
 */
public class ConcreteHandler1 extends Handler {

 @Override
 public void handleRequest(Request request) {
  System.out.println("inside handler 1");
  if(request.getState().startsWith("one")){
   
   //handle request
   
  }else{
   super.successor.handleRequest(request);
  }
 }

}

package cor.pattern;
/**
 * 2nd handler
 *
 */
public class ConcreteHandler2 extends Handler {

 @Override
 public void handleRequest(Request request) {
  System.out.println("inside handler 2");

  if (request.getState().startsWith("two")) {

   // handle request

  } else {
   super.successor.handleRequest(request);
  }
 }
}

package cor.pattern;

/**
 * Request object
 *
 */
public class Request {
 private String state;

 public Request(String state) {
  this.state = state;
 }

 public String getState() {
  return state;
 }
}

public static void main(String[] args){
  Request r = new Request("two, requestParam");
  
  Handler h1 = new ConcreteHandler1();
  Handler h2 = new ConcreteHandler2();
  
  h1.successor = h2;
  h1.handleRequest(r);
 }
*Ignore poor abstraction/encapsulation in above classes.


COR Limitations
  • Only one object in the chain handles the request
  • There is no default handler; some of the request might go unhandled 

 

Practical Implementation

Practically it will be more beneficial to relax one condition from COR intent - ".. Chain the receiving objects and pass the request along the chain until an object handles it".

So above limitation can be relaxed to allow more than one object to handle a request. So each handler can handle a request, pass it to the successor or can do both. Servlet filters are COR implementations which allow more than one filters to intercept and process the HTTP request. Servlet filters are very handy in providing security, logging, or performing some common operations on each request. So http request can get handled by more than one filter (or handler).


Benefits of COR

  • Sender and receivers are loosely coupled
  • The chain of handlers can be modified dynamically, independent of sender and request.
  • Sender is oblivious of number of receivers/handlers

References

----------
do post your feedback !!!

No comments:

Post a Comment