Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.

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.

Problem

This pattern is recommended when multiple objects can handle a request and the handler doesn’t have to be a specific object. Also, the handler is determined at runtime. Please note that a request not handled at all by any handler is a valid use case
COR
In the above UML Class Diagram of Chain of responsibility Design Pattern it consists of the following classes, interfaces and objects:

  • Handler: Handler is an interface which will primarily recieve the request and dispatches the request to chain of handlers.It has reference of only first handler in the chain and knows nothing about the remaining handler.
  • Concrete handlers: These are actual handlers of the request chained in some sequential order.
  • Client: Client is a request creator and this will access the handler to handle it.
    ConcreteHandler1 and ConcreteHandler2 both process the requests for which they are responsible.In case the ConcreteHandler1 can not handle the request, the request is passed to the ConcreteHandler2 which is linked to ConcreteHandler1 . The chain objects just need to know how to transmit the request to other objects.

Implementing Chain of responsibility design pattern

Let’s see the example of chain of responsibility pattern in JAVA and then we will proceed to implement an example of this pattern.
In this example, I will make the right calculations based of a String request.

public class Numbers {

	private int number1;
	private int number2;
	private String calculWanted;

	public Numbers(int number1, int number2, String calculWanted) {

		this.number1 = number1;
		this.number2 = number2;
		this.calculWanted = calculWanted;
	}

	public int getNumber1() {
		return number1;
	}

	public int getNumber2() {
		return number2;
	}

	public String getCalculWanted() {
		return calculWanted;
	}

}

This object Numbers will contain 2 numbers and a calculation to perform in the form of a String.

public interface Chain {

	public void setNextChain(Chain nextChain);
	public void calculate(Numbers request);
    
}
}

Our Interface Chain should have a method to define the next handler in the chain and the method that will process the request.

Now we create different classes that will implement the Chain interface and provide implementation of methods
AddNumbers.java

public class AddNumbers implements Chain {
	private Chain nextInChain;

	@Override
	public void setNextChain(Chain nextChain) {
		this.nextInChain = nextChain;

	}

	@Override
	public void calculate(Numbers request) {
		if (request.getCalculWanted() == "add") {
			System.out.println(request.getNumber1() + " + " + request.getNumber2() + " = "
					+ (request.getNumber1() + request.getNumber2()));
		} else {
			nextInChain.calculate(request);
		}

	}

}

SubstructNumber.java

public class SubstructNumber implements Chain{
	private Chain nextInChain;

	@Override
	public void setNextChain(Chain nextChain) {
		this.nextInChain = nextChain;

	}

	@Override
	public void calculate(Numbers request) {
		if (request.getCalculWanted() == "sub") {
			System.out.println(request.getNumber1() + " - " + request.getNumber2() + " = "
					+ (request.getNumber1() - request.getNumber2()));
		} else {
			nextInChain.calculate(request);
		}

	}


}

MultNumbers.java

public class MultNumbers implements Chain {
	private Chain nextInChain;

	@Override
	public void setNextChain(Chain nextChain) {
		this.nextInChain = nextChain;

	}

	@Override
	public void calculate(Numbers request) {
		if (request.getCalculWanted() == "mult") {
			System.out.println(request.getNumber1() + " * " + request.getNumber2() + " = "
					+ (request.getNumber1() * request.getNumber2()));
		} else {
			nextInChain.calculate(request);
		}

	}

}

Note that each implementation is trying to process the request and based on the calculWanted (String),if one of the chain not able to handle it, it sends the request to the next handler in chain to process the remaining request. If the handler is not able to process anything, it just forwards the same request to the next chain.

Advantages (+)
• Decouples sender from receiver. – The pattern decouples the sender of a request from a particular receiver (handler) by sending the request to a chain of handlers.
• Makes changing the chain of handlers easy. – The chain of handlers can be changed at run-time (handlers can be added to and removed from the chain).

References: