Sunday 31 December 2017

Chain of Responsibility Design Pattern

It’s one of behavior design pattern


Chain of responsibility pattern is used to achieve loose coupling in software design where a request from client is passed to a chain of objects to process them. Then the object in the chain will decide themselves who will be processing the request and whether the request is required to be sent to the next object in the chain or not.

Example: - We know that we can have multiple catch blocks in a try-catch block code. Here every catch block is kind of a processor to process that particular exception.

Another real-time scenario was request approval process




Components in diagram are:
  • Handler: An abstract class or Interface which defines request handling behavior which handles request
  • ConcreteHandlers: Define more specific behavior for handling request, if they can’t handle it, they will simply call super class handle method.
  • Client: Instantiates all concrete handlers and chains them dynamically.

DPRequest.java
package dp;

public class DPRequest {
       private String requestType;
       private String isItApprovedByLevel2;
       private String isItApprovedByLevel1;

       public String getRequestType() {
              return requestType;
       }

       public void setRequestType(String requestType) {
              this.requestType = requestType;
       }

       public String getIsItApprovedByLevel2() {
              return isItApprovedByLevel2;
       }

       public void setIsItApprovedByLevel2(String isItApprovedByLevel2) {
              this.isItApprovedByLevel2 = isItApprovedByLevel2;
       }

       public String getIsItApprovedByLevel1() {
              return isItApprovedByLevel1;
       }

       public void setIsItApprovedByLevel1(String isItApprovedByLevel1) {
              this.isItApprovedByLevel1 = isItApprovedByLevel1;
       }
      

}

Approvals.java
package dp;

public interface Approvals {
       public void nextAction(Approvals next);
       public void process(DPRequest request);

}

Supervisor.java
package dp;

public class Supervisor implements Approvals{
       private Approvals next;
       @Override
       public void nextAction(Approvals next) {
              // TODO Auto-generated method stub
              this.next=next;
       }

       @Override
       public void process(DPRequest request) {
              // TODO Auto-generated method stub
              if("Service Type".equals(request.getRequestType())){
                     System.out.println("Supervisor accepted Service Type");
                     request.setIsItApprovedByLevel1("Y");
              }else if("Leave".equals(request.getRequestType())){
                     System.out.println("Supervisor accepted Leave Type");
                     request.setIsItApprovedByLevel1("Y");
              }
                     next.process(request);
             
       }

      

}

Accountant.java
package dp;

public class Accountant implements Approvals{
       private Approvals next;
       @Override
       public void nextAction(Approvals next) {
              // TODO Auto-generated method stub
              this.next=next;
       }

       @Override
       public void process(DPRequest request) {
              // TODO Auto-generated method stub
              if("Salary Advance".equals(request.getRequestType()) && "Y".equals(request.getIsItApprovedByLevel2())){
                     System.out.println("Accountant accepted Service Type");
                    
              }else{
                     System.out.println("Salary Advance request is not approved by Manager");
                     request.setIsItApprovedByLevel1("N");
                     next.process(request);
              }
       }

}


Manager.java
package dp;

public class Manager implements Approvals{

       private Approvals next;
       @Override
       public void nextAction(Approvals next) {
              // TODO Auto-generated method stub
              this.next=next;
       }


       @Override
       public void process(DPRequest request) {
              // TODO Auto-generated method stub
              if("Salary Advance".equals(request.getRequestType()) && "N".equals(request.getIsItApprovedByLevel1())){
                     request.setIsItApprovedByLevel2("Y");
                     System.out.println("Manager accepted Service Type");
              }else if(!"Salary Advance".equals(request.getRequestType()) && "Y".equals(request.getIsItApprovedByLevel1())){
                     System.out.println("Manager accepted Service Type");
              }
              if(null!=request){
                     next.process(request);
              }
                    
             
       }

}

ChainResponEx.java
package dp;

public class ChainResponEx{

       public static void main(String args[]){
              DPRequest request=new DPRequest();
              Approvals s=new Supervisor();
              Approvals a=new Accountant();
              Approvals m=new Manager();
              request.setRequestType("Salary Advance");
       //     s.nextAction(m);
              a.nextAction(m);
              m.nextAction(a);
              //s.process(request);
              a.process(request);
              m.process(request);
       }
}


Output:-

Salary Advance request is not approved by Manager
Manager accepted Service Type
Accountant accepted Service Type

  • DPRequest is the actual request object that will be created by client and passed to chain of responsibilities.
  • Approvals an interface which nextAction method, to handling behavior which handles request.
  • Supervisor ,Accountant and Manager are concrete sub classes of Approver, which provide their own specific behavior based on our conditions for approval authorization. If they can’t handle Request, they simply call next.process(request);, which in turn calls method from nextProcess.
  • ChainResponEx is actual client which instantiates all responsibilities and create a chain by setting next approver for each responsibility.