Motivation :-
The idea of this pattern is to decouple senders and receivers by giving multiple objects a chance to handle a request. The request gets passed along a chain of objects until one of them handles it. The first object in the chain receives the request and either handles it or forwards it to the next candidate on the chain, which does likewise. The object that made the request has no explicit knowledge of who will handle it.
When you should use this :-
This pattern is recommended when either of the following scenarios occur in your application –
1. You want to issue a request to one of several objects without specifying the receiver explicitly.
2. Multiple objects can handle a request. The handler should be ascertained in the runtime automatically.
3. A request not being handled is an acceptable outcome.
Practical usage of the pattern –
1. The pattern is used in windows systems to handle events generated from the keyboard or mouse.
2. Exception handling systems also implement this pattern, with the runtime checking if a handler is provided for the exception through the call stack. If no handler is defined, the exception will cause a crash in the program, as it is unhandled.
3. In JavaEE, the concept of Servlet filters implement the Chain of Responsibility pattern, and may also decorate the request to add extra information before the request is handled by a servlet.
Sample Code :-
Abstract rule handler –
package com.sanjit; import java.util.Map; import com.sanjit.rule.Rule; /** * Abstract rule handler class. * * @author Sanjit Mohanty * @version 0.1 * * * Revision History: * VERSION DATE AUTHOR COMMENT * 0.1 20-May-2015 Sanjit Mohanty initial create * * */ public abstract class RuleHandler { protected RuleHandler nextRuleHandler; public RuleHandler() { nextRuleHandler = null; } public void setNextRuleHandler(RuleHandler nextRuleHandler) { this.nextRuleHandler = nextRuleHandler; } protected abstract boolean canHandle(Rule rule); protected abstract Map processRule(Rule rule); public Map populateRuleData(Rule rule) { Map result; if (canHandle(rule)) { result = processRule(rule); } else { if (null != nextRuleHandler) { result = nextRuleHandler.populateRuleData(rule); } else { result = new UnknownRuleHandler().process(rule); } } return result; } }
First concrete rule handler –
package com.sanjit; import java.util.HashMap; import java.util.Map; import com.sanjit.rule.Rule; /** * Concrete rule handler 1 class. * * @author Sanjit Mohanty * @version 0.1 * * * Revision History: * VERSION DATE AUTHOR COMMENT * 0.1 20-May-2015 Sanjit Mohanty initial create * * */ public class ConcreteRuleHandler1 extends RuleHandler { @Override protected Map process(Rule rule){ Map ruleData = new HashMap(); // Your processing logic goes here... return ruleData; } @Override protected boolean canHandle(Rule rule) { // TODO Auto-generated method stub return (rule instanceof ConcreteRuleHandler1); } }
Second concrete rule handler –
package com.sanjit; /** * Concrete rule handler 2 class. * * @author Sanjit Mohanty * @version 0.1 * * * Revision History: * VERSION DATE AUTHOR COMMENT * 0.1 20-May-2015 Sanjit Mohanty initial create * * */ public class ConcreteRuleHandler2 extends RuleHandler { @Override protected Map process(Rule rule){ Map ruleData = new HashMap(); // Your processing logic goes here... return ruleData; } @Override protected boolean canHandle(Rule rule) { // TODO Auto-generated method stub return (rule instanceof ConcreteRuleHandler2); } }
Third concrete rule handler –
package com.sanjit; /** * Concrete rule handler 3 class. * * @author Sanjit Mohanty * @version 0.1 * * * Revision History: * VERSION DATE AUTHOR COMMENT * 0.1 20-May-2015 Sanjit Mohanty initial create * * */ public class ConcreteRuleHandler3 extends RuleHandler { @Override protected Map process(Rule rule){ Map ruleData = new HashMap(); // Your processing logic goes here... return ruleData; } @Override protected boolean canHandle(Rule rule) { // TODO Auto-generated method stub return (rule instanceof ConcreteRuleHandler3); } }
Client class –
package com.sanjit; import java.util.Map; import com.sanjit.rule.Rule; /** * Client class. * * @author Sanjit Mohanty * @version 0.1 * * * Revision History: * VERSION DATE AUTHOR COMMENT * 0.1 20-May-2015 Sanjit Mohanty initial create * * */ public class RuleClient { private ConcreteRuleHandler1 concreteRuleHandler1 = null; private ConcreteRuleHandler2 concreteRuleHandler2 = null; private ConcreteRuleHandler3 concreteRuleHandler3 = null; public RuleClient () { super(); // TODO Auto-generated constructor stub concreteRuleHandler1 = new ConcreteRuleHandler1(); concreteRuleHandler2 = new ConcreteRuleHandler2(); concreteRuleHandler3 = new ConcreteRuleHandler3(); concreteRuleHandler1.setNextRuleHandler(concreteRuleHandler2); concreteRuleHandler2.setNextRuleHandler(concreteRuleHandler3); } private void populateRuleSpecificValues(Rule rule) { Map ruleData = null; RuleHandler ruleHandler = concreteRuleHandler1; ruleData = ruleHandler.populateRuleData(rule); } }