Chain of Responsibility Design Pattern in Java

The Chain of Responsibility is known as a behavioral pattern, as it is used to manage algorithms, relationships and responsibilities between objects. The Chain of Responsibility pattern consists of a series of processing objects where each object containing the type of commands it can handle. Each object in the series either does its own task or passes to the next object if it cannot handle the request. A mechanism also exists for adding new processing objects to the end of this chain or series.

In this pattern objects in the chain are linked, typically as a one-directional linked list, with a next reference from one node to the next node. The request is passed along the chain, from one object to the next, until an object (a handler or receiver) handles it. When the request is handled, it is no longer passed on to the next level. If no object handles the request, a default object at the end of the chain can be made to handle it, or it may be that no object handles the request. Sometimes, if required, multiple objects may handle the request.

Class Diagram

Chain of Responsibility Pattern in Java

Example
Exception handling in Java is based on Chain of Responsibility pattern.
So in this pattern:

Sender does not know which object in the chain will serve its request
Each node in the chain may decide to serve the request such as catching an exception and wrapping it with an application specific exception
Each node can forward the request like throwing exception to the immediate caller
None of the node can serve the request such as leaves the job with the caller

Suppose the code written throws an StringIndexOutOfBoundsException. This exception will get caught at correct level when an exception occurs due to some bug in source code. Suppose, we have an exception which is an application specific in the catch block. This will not be caught by what we have an application specific exception. It will find for an Exception class and will be caught by that as both the application specific exception and the StringIndexOutOfBoundsException are sub-classes of the class Exception.

Once the exception gets caught, then it will not look for any other exception. Now this is the reason, sometimes why we get an “Exception is unreachable” message when we try to add a catch block with the exception below the parent exception.

Implementation
I will show you steps for placing an order for an online product seller. Steps for placing an order are shown as below:
1. Select a Product from online store
2. Register yourself for placing an order
3. Enter your billing or shipping address where your product will be delivered
4. Make payment for your order
5. Get the confirmation message once your order has been successfully placed
Create an interface

package com.roytuts.designpattern.chainofresponsibility;
/**
 * The Chain of Responsibility Pattern has a group of objects that are able to solve a problem among them based on some internal communication. If one
 * of objects is unable to solve it, it passes the problem on to the next object in the chain
 *
 * @author roytuts.com
 *
 */
public interface OrderHandler {
  /**
   * It passes the data to next Handler in chain if one fails to handle the problem
   *
   * @param handler
   */
  void nextHandler(OrderHandler handler);
  /**
   * It processes the request and if it fails it just passes it on to the next Handler in the chain.
   *
   * @param request
   */
  public void processRequest(OrderAction request);
}

Create a class

package com.roytuts.designpattern.chainofresponsibility;
public class OrderAction {
  private String action;
  public OrderAction(String action) {
    this.action = action;
  }
  public String getAction() {
    return action;
  }
  public void setAction(String action) {
    this.action = action;
  }
}

Create five different implementation classes for placing an order

package com.roytuts.designpattern.chainofresponsibility;
public class ProductSelection implements OrderHandler {
  protected OrderHandler orderHandler;
  @Override
  public void nextHandler(OrderHandler orderHandler) {
    this.orderHandler = orderHandler;
  }
  @Override
  public void processRequest(OrderAction request) {
    if ("selectprod".equalsIgnoreCase(request.getAction())) {
      System.out.println("Select a product you would like to buy");
    } else {
      orderHandler.processRequest(request);
    }
  }
}
package com.roytuts.designpattern.chainofresponsibility;
public class Registration implements OrderHandler {
  protected OrderHandler orderHandler;
  @Override
  public void nextHandler(OrderHandler handler) {
    this.orderHandler = handler;
  }
  @Override
  public void processRequest(OrderAction request) {
    if ("register".equalsIgnoreCase(request.getAction())) {
      System.out.println("Register yourself for placing an order");
    } else {
      orderHandler.processRequest(request);
    }
  }
}
package com.roytuts.designpattern.chainofresponsibility;
public class BillingInfo implements OrderHandler {
  protected OrderHandler orderHandler;
  @Override
  public void nextHandler(OrderHandler handler) {
    this.orderHandler = handler;
  }
  @Override
  public void processRequest(OrderAction request) {
    if ("billinginfo".equalsIgnoreCase(request.getAction())) {
      System.out.println("Enter billing or shipping information");
    } else {
      orderHandler.processRequest(request);
    }
  }
}
package com.roytuts.designpattern.chainofresponsibility;
public class Payment implements OrderHandler {
  protected OrderHandler orderHandler;
  @Override
  public void nextHandler(OrderHandler handler) {
    this.orderHandler = handler;
  }
  @Override
  public void processRequest(OrderAction request) {
    if ("payment".equalsIgnoreCase(request.getAction())) {
      System.out.println("Make payment for your order");
    } else {
      orderHandler.processRequest(request);
    }
  }
}
package com.roytuts.designpattern.chainofresponsibility;
public class Confirmation implements OrderHandler {
  protected OrderHandler orderHandler;
  @Override
  public void nextHandler(OrderHandler handler) {
    this.orderHandler = handler;
  }
  @Override
  public void processRequest(OrderAction request) {
    if ("confirm".equalsIgnoreCase(request.getAction())) {
      System.out.println("Your order has been placed successfully");
    } else {
      System.out.println("Request cannot be processed by any one of handlers");
    }
  }
}

Create a test class for testing the pattern

package com.roytuts.designpattern.chainofresponsibility;
public class ChainOfResponsibilityTest {
  /**
   * @param args
   */
  public static void main(String[] args) {
    OrderHandler orderHandler1 = new ProductSelection();
    OrderHandler orderHandler2 = new Registration();
    OrderHandler orderHandler3 = new BillingInfo();
    OrderHandler orderHandler4 = new Payment();
    OrderHandler orderHandler5 = new Confirmation();
    orderHandler1.nextHandler(orderHandler2);
    orderHandler2.nextHandler(orderHandler3);
    orderHandler3.nextHandler(orderHandler4);
    orderHandler4.nextHandler(orderHandler5);
    OrderAction orderAction = new OrderAction("selectprod");
    orderHandler1.processRequest(orderAction);
    orderAction = new OrderAction("register");
    orderHandler1.processRequest(orderAction);
    orderAction = new OrderAction("billinginfo");
    orderHandler1.processRequest(orderAction);
    orderAction = new OrderAction("payment");
    orderHandler1.processRequest(orderAction);
    orderAction = new OrderAction("confirm");
    orderHandler1.processRequest(orderAction);
    orderAction = new OrderAction("proddelivered");
    orderHandler1.processRequest(orderAction);
  }
}

Output

Select a product you would like to buy
Register yourself for placing an order
Enter billing or shipping information
Make payment for your order
Your order has been placed successfully
Request cannot be processed by any one of handlers

That’s all. Thank you for your reading.

Leave a Reply

Your email address will not be published. Required fields are marked *