Chain of Responsibility Design Pattern

Amila Iroshan
The Fresh Writes
Published in
7 min readAug 1, 2023

Definition

Chain of responsibility pattern belongs to the behavioral design pattern and that allows you to pass the 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.

In brief this design pattern avoid coupling sender and receiver.
Sender do not know who is the receiver and receiver do not know who is the sender. Receiver can perform their job without knowing sender and sender can perform his job without knowing reciever.
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. As well as we can change the order of receivers without change the core implementation.

Java Real Use Cases

1). Java api logger is best example for chain of responsibility. If you set log levels it will print above the log level and does not print below the log level. The log level Order/Priority as below

Trace < Debug < Info < Warn < Error < Fatal

2). Spring security authentication filters are another example of implementation of Chain of responsibility pattern.
Each filters have their own business and perform operation on incoming request.

Chain Of Responsibility in Security Filters

UML Diagram

UML Diagram

Client: Sends requests to the first object in the chain that may handle the command.

Handler: This can be an interface which will primarily receive the request and dispatches the request to a chain of handlers. It has reference to the only first handler in the chain and does not know anything about the rest of the handlers.

Concrete handlers: These are actual handlers of the request chained and responsible for handle the requests they receive. If a particular handler cannot handle the request, it sends the request to its successor.

Real World Use Case for Implement the Chain of Responsibility

Let’s get a real-world example to understand this design pattern. I’m going to implement a calculator for calculate local bank’s fixed deposit amount. It is depends on bank type and time period of the deposit.

# First create a POJO class called FixedDeposit and created ENUM for hold the bank types.

public class FixedDeposit {

private Bank bank;
private int period;
private BigDecimal amount;
private BigDecimal interest;
private BigDecimal fullAmount;

public FixedDeposit(Bank bank, int period, BigDecimal amount) {
super();
this.bank = bank;
this.period = period;
this.amount = amount;
}

//Getters and Setters Here
public enum Bank {
BOC,
PEOPLES,
SAMPATH,
COMMERCIAL,
HNB;
}

# Then created a Handler class which is abstract class and it has a abstract method called calculateFixedDeposit(FixedDeposit fixedDeposit) and created the “Handler” object within the class, because the handler should know about its next handler.

public abstract class Handler {

public Handler handler;
public void setHandler(Handler handler) {
this.handler = handler;
}
public abstract FixedDeposit calculateFixedDeposit(FixedDeposit fixedDeposit);
}

# After that created concrete classes for each concrete handlers. In my scenario I listed below my concrete handlers.Each concrete handlers shoul extends Handler class and implement it’s own business logic. If request not related to this concrete handler then passed it to next handler.

public class BOCHandler extends Handler {

@Override
public FixedDeposit calculateFixedDeposit(FixedDeposit fixedDeposit) {

if(fixedDeposit.getBank().equals(Bank.BOC)) {
int period=fixedDeposit.getPeriod();
BigDecimal amount=fixedDeposit.getAmount();
if(period <=2) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.135)));
}
else if(period > 2 && period < 6) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.15)));
}
else if(period >=6 && period < 12) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.1475)));
}
else {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.145)));
}
fixedDeposit.setFullAmount(amount.add(fixedDeposit.getInterest()));
return fixedDeposit ;
}
else {
return handler.calculateFixedDeposit(fixedDeposit);
}
}
public class CommercialBankHandler extends Handler{

@Override
public FixedDeposit calculateFixedDeposit(FixedDeposit fixedDeposit) {
if(fixedDeposit.getBank().equals(Bank.COMMERCIAL)) {
int period=fixedDeposit.getPeriod();
BigDecimal amount=fixedDeposit.getAmount();
if(period <=1) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.100)));
}
else if(period > 1 && period <= 2) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.105)));
}
else if(period > 2 && period < 6) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.125)));
}
else if(period >=6 && period < 12) {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.130)));
}
else {
fixedDeposit.setInterest(amount.multiply(BigDecimal.valueOf(.130)));
}
fixedDeposit.setFullAmount(amount.add(fixedDeposit.getInterest()));
return fixedDeposit ;

}
else {
return handler.calculateFixedDeposit(fixedDeposit);
}
}
}

# Here is Demo class where listed handler in order and call it.

@SpringBootApplication
public class ChainOfResponsibilityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ChainOfResponsibilityDemoApplication.class, args);

InitiateHandler initiate=new InitiateHandler();
BOCHandler boc=new BOCHandler();
PeoplesBankHandler peoples=new PeoplesBankHandler();
HNBHandler hnb=new HNBHandler();
CommercialBankHandler com=new CommercialBankHandler();

initiate.setHandler(boc);
boc.setHandler(peoples);
peoples.setHandler(hnb);
hnb.setHandler(com);

traceDepositInfo(initiate.calculateFixedDeposit(new FixedDeposit(Bank.BOC, 5, BigDecimal.valueOf(100))));
}

public static void traceDepositInfo(FixedDeposit fixedDeposit) {
System.out.printf("The %s Bank interest is : %.2f for given amount : %.2f%n", fixedDeposit.getBank(),fixedDeposit.getInterest(),fixedDeposit.getAmount() );
}
}

# Final Output as below.

 .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.15-SNAPSHOT)

2023-08-01 14:42:18.875 INFO 13864 --- [ main] e.C.ChainOfResponsibilityDemoApplication : Starting ChainOfResponsibilityDemoApplication using Java 17.0.4.1 on AMILA with PID 13864 (C:\Users\Asus\Documents\projects\ChainOfResponsibilityDemo\target\classes started by Asus in C:\Users\Asus\Documents\projects\ChainOfResponsibilityDemo)
2023-08-01 14:42:18.883 INFO 13864 --- [ main] e.C.ChainOfResponsibilityDemoApplication : No active profile set, falling back to 1 default profile: "default"
2023-08-01 14:42:20.725 INFO 13864 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-08-01 14:42:20.738 INFO 13864 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-08-01 14:42:20.738 INFO 13864 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.78]
2023-08-01 14:42:20.862 INFO 13864 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-08-01 14:42:20.862 INFO 13864 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1910 ms
2023-08-01 14:42:21.339 INFO 13864 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-08-01 14:42:21.354 INFO 13864 --- [ main] e.C.ChainOfResponsibilityDemoApplication : Started ChainOfResponsibilityDemoApplication in 2.952 seconds (JVM running for 3.542)
The BOC Bank interest is : 15.00 for given amount : 100.00

Conclusion

In this example I showed how to use the chain of responsibility pattern to decouple the business logic from the main method and how to send the request to different receiver, which the sender doesn’t even know.

You can find the complete code for this example on my GitHub

Thank you for read this article and If you like this article, do follow and clap 👏🏻.Happy coding, Cheers !!😊😊

Do support our publication by following it

--

--

Amila Iroshan
The Fresh Writes

Software Engineer | Open Source Contributor | Tech Enthusiast