Friday, May 2, 2014

Chain of responsibility design pattern

Before dive into the details, let me explain a real time use case for using Chain of responsibility design pattern.

Lets say you are working on a online internet banking solution.What are the typical actions take place after you submit the transaction(It may be a fund transfer or bill payment or remittance to another country)? The money will be debited(Need to update the balance in database),send an xml to back office(probably your front end and back office in different technologies and you use xml consisting of your transaction details to communicate with the back office where the real calculations will take place) and a SMS update to customer's registered mobile and similarly an EMAIL to customer's registered email id. These are all different actions and different components need to process these actions.We can chain these actions and process the request one by one.Lets say if a particular end user not registered for SMS or EMAIL then he wont be getting these alerts as this pattern allow us to skip those requests.

Another use case, lets say in a bank an associate branch manager can approve an amount of 1 lakh loan and any amount more than that requires a branch manager's approval where he can approve 10 lakhs and if its more than that amount its require an approval from the director.So the client doesn't know who actually process the request.

One of the most famous use case for chain of responsibility design pattern is ATM.



If you are having similar kind of above use cases, chain of responsibility is your best bet.

Chain of responsibility is a behavioral design pattern. In this pattern a set of  handlers are chained to handle a request coming from the client object.The first handler process the request and its forwarded to the next handler in the chain.Please note if the first handler process the request or unable to process the request will forwarded to the to the next handler.This process will continue till it reaches the last handler in the chain.




As depicted in the above image, the client object only knows about the abstract handler and does't aware which concrete handler really process its request.This way this pattern provide loose coupling between the objects.You can add new handlers with out actually touching your client code when a new requirement comes.

Let's see Chain of responsibility design pattern in action.

In this example we create a chain of different handlers such that depending on the handler type being passed to the handler, the handler has to decide whether its going to process the request or  pass the request to its successor handle to take action. The handlers we have are  Database Handler, SMS Handler, EMAIL Handler and XML Handler. The handler logic in each of these handler doesn’t process any real logic instead it just prints out a message stating who is handing the request for which request. We then populate handler codes of different handlers into a list and then iterate through them passing the handle code to the first handler in the list.

Our Base Handler

package ramesh.chainOfResponsibility;  
 /**  
  * @author RameshM  
  *  
  */  
 public class BaseHandler {  
 private BaseHandler successor;  
 public void process(String serviceName) {  
 if (getSuccessor() != null) {  
 getSuccessor().process(serviceName);  
 } else {  
 System.out.println("Unable to find the correct Service Handler: "  
 + serviceName);  
 }  
 }  
 BaseHandler getSuccessor() {  
 return successor;  
 }  
 void setSuccessor(BaseHandler successor) {  
 this.successor = successor;  
 }  
 }  
We would now create different handlers for handle different request namely-Database handler, SMS handler, EMAIL handler and XML Handler and these extend from the Base Handler class and override the process method. I have kept the implementation of different handlers simple and these methods evaluate if the request has the string type they are looking for. If a particular handler is unable to process the request i.e. the request type is not what it is looking for, then the parent method handles such requests. The handler method in the parent class just invokes the same method on the successor handler.

DatabaseHandler which handles actions related to Database.

package ramesh.chainOfResponsibility;  
 public class DatabaseHandler extends BaseHandler {  
 public DatabaseHandler(BaseHandler successor) {  
 this.setSuccessor(successor);  
 }  
 @Override  
 public void process(String serviceName) {  
 if (serviceName.equals("DATABASE")) {  
 System.out.println("DATABASE Handler handling the request: "  
 + serviceName);  
 } else {  
 super.process(serviceName);  
 }  
 }  
 }  
Email Handler handles request related to Email actions
package ramesh.chainOfResponsibility;  
 public class EmailHandler extends BaseHandler {  
 public EmailHandler(BaseHandler successor) {  
 this.setSuccessor(successor);  
 }  
 @Override  
 public void process(String serviceName) {  
 if (serviceName.equals("EMAIL")) {  
 System.out.println("EMAIL Handler handling the request: "  
 + serviceName);  
 } else {  
 super.process(serviceName);  
 }  
 }  
 }  
SMS handler handles for SMS related actions
package ramesh.chainOfResponsibility;  
 /**  
  * @author RameshM  
  *  
  */  
 public class SMSHandler extends BaseHandler {  
 public SMSHandler(BaseHandler successor) {  
 this.setSuccessor(successor);  
 }  
 @Override  
 public void process(String serviceName) {  
 if (serviceName.equals("SMS")) {  
 System.out.println("SMS Handler handling the request: "  
 + serviceName);  
 } else {  
 super.process(serviceName);  
 }  
 }  
 }  
XML Handler handles XML related actions
package ramesh.chainOfResponsibility;  
 public class XMLHandler extends BaseHandler {  
 @Override  
 public void process(String serviceName) {  
 if (serviceName.equals("XML")) {  
 System.out.println("XML Handler handling the request: "  
 + serviceName);  
 } else {  
 super.process(serviceName);  
 }  
 }  
 }  
Now that we have all the handlers setup, we need to create a chain of handlers. In this example the chain we create is: Database handler-> SMS handler -> Email handler-> XML handler.Lets see the code for the client class which creates a list of handler codes and then creates the chain which I just described.
package chainOfResponsibility;  
 import java.util.LinkedList;  
 import java.util.List;  
 public class ChainOfResponsibilityDemo {  
 /**  
  * @param args  
  */  
 public static void main(String[] args) {  
 List<String> handlers = populateServiceNames();  
 // No successor for this handler since this is the last in the chain  
 BaseHandler xmlHandler = new XMLHandler();  
 // xml handler is the successsor for email handler  
 BaseHandler emailHandler = new EmailHandler(xmlHandler);  
 // email handler is the successor for sms handler  
 BaseHandler smsHandler = new SMSHandler(emailHandler);  
 // database handler is the first handler in the chain which will invoke  
 // SMS handler  
 BaseHandler dbHandler = new DatabaseHandler(smsHandler);  
 for (String str : handlers) {  
 dbHandler.process(str);  
 }  
 }  
 private static List<String> populateServiceNames() {  
 List<String> handlerCodes = new LinkedList<String>();  
 handlerCodes.add("DATABASE");  
 handlerCodes.add("SMS");  
 handlerCodes.add("NOHANDLER");  
 handlerCodes.add("EMAIL");  
 handlerCodes.add("XML");  
 return handlerCodes;  
 }  
 }  
Lets run the program and see the output.As you can see the main program, the client only knows the base handler and it forward the request to first handler in the chain and the chain continue till it reaches the last handler.As you can see i added a handler code "NOHANDLER" in list of handler codes just to make sure that if there is not handler specified ,then our base handler handles and prints there is no handler available to process the request. All done... lets see the output below...

Output:

DATABASE Handler handling the request: DATABASE
SMS Handler handling the request: SMS
Unable to find the correct Service Handler: NOHANDLER
EMAIL Handler handling the request: EMAIL
XML Handler handling the request: XML

Disadvantages using Chain of responsibility pattern.

The chain should be created carefully otherwise there might be a case where the handler might not pass the request to the next handler or there wont be any handlers to process the request.

Implementation of this pattern in Java and Java EE API

java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()


Thanks for visiting my blog!!!!!!!!!!

No comments:

Post a Comment