Chain of Responsibility in 5 Simple Steps

Rakesh singhania
3 min readFeb 5, 2024

The Chain of Responsibility pattern is a behavioural design pattern where a request is passed through a chain of handlers, and each handler decides either to process the request or pass it along the chain.

Scenario:

Consider a scenario where you have a series of processors, each responsible for a specific aspect of request handling. The order and responsibility of these processors may vary based on the requirements.

In a Spring Boot application, you might encounter scenarios where multiple components or services need to process a request, and the order or responsibility of each component can vary. The Chain of Responsibility pattern helps in handling these scenarios in a flexible and maintainable way.

Photo by R Fiorentino on Unsplash

Here’s a simple example in Java Spring Boot to illustrate the Chain of Responsibility pattern. Let’s consider a scenario where we have different processors to handle a request, and each processor can decide whether to process the request or pass it to the next processor:

  1. Define the Request class:
public class Request {
private String type;

public Request(String type) {
this.type = type;
}

public String getType() {
return type;
}
}

2. Create the Handler interface:

public interface RequestProcessor {
boolean process(Request request);
}

3. Implement concrete handlers:


@Component
public class FirstProcessor implements RequestProcessor {

@Override
public boolean process(Request request) {
if (request.getType().equals("AUTHENTICATION")) {
System.out.println("Handling Authentication Request");
// Logic for handling authentication
}else{
nextHandler.handleRequest(request);
}
}
}
@Component
public class SecondProcessor implements RequestProcessor {
@Override
public void process(Request request) {

if (request.getType().equals("AUTHORIZATION")) {
System.out.println("Handling Authorization Request");
// Logic for handling authorization
} else {
// Pass the request to the next handler in the chain
nextHandler.handleRequest(request);
}
}
}

If a processor handles the request, the chain is broken, and further processors are not called.

4. Create a Chain of Responsibility to handle all requests:

@Service
public class RequestService {

private final List<RequestProcessor> processors;

@Autowired
public RequestService(List<RequestProcessor> processors) {
this.processors = processors;
}

public void processRequest(Request request) {
for (RequestProcessor processor : processors) {
if (processor.process(request)) {
// Request handled, break the chain
break;
}
}
}
}

The RequestService is responsible for orchestrating the processing of a request through the chain of processors.

Usage:

Now, let’s use this chain of processors in a Spring Boot application:

5. Usage in a Spring Boot Application:



@SpringBootApplication
public class ChainOfResponsibilityExampleApplication implements CommandLineRunner {

@Autowired
private RequestService requestService;

public static void main(String[] args) {
SpringApplication.run(ChainOfResponsibilityExampleApplication.class, args);
}

@Override
public void run(String... args) {
// Create a sample request
Request request = new Request("Sample Request Data");

// Process the request through the chain of processors
requestService.processRequest(request);
}
}

Why Chain of Responsibility:

  1. Flexibility and Extensibility: The Chain of Responsibility pattern allows you to add or remove processors without modifying existing code. This promotes flexibility and extensibility in handling different types of requests.
  2. Loose Coupling: The pattern promotes loose coupling between the sender of the request (RequestService) and the handlers (RequestProcessor implementations). Each processor is only aware of the next processor in the chain, minimizing dependencies.
  3. Dynamic Processing Order: The order of processors and their responsibilities can be easily changed at runtime without affecting the core logic of the application. This is useful when requirements dictate a dynamic order of processing.
  4. Single Responsibility Principle: Each processor focuses on a specific aspect of handling the request, adhering to the Single Responsibility Principle. This makes the code modular and easier to maintain.

--

--

Rakesh singhania

As a student of technology, each day I take a single step forward on the path of learning.