Java 3 min read

The Chain of Responsibility Pattern: Pass It Down

Master the Chain of Responsibility Pattern in Java. Learn how to pass requests along a chain of handlers until one of them handles it.

MR

Moshiour Rahman

Advertisement

The Problem: Rigid Coupling

Imagine you are building a Login system. You need to verify:

  1. Is the user banned?
  2. Is the password correct?
  3. Is the IP allowed?
  4. Do they have 2FA enabled?

If you put all this in one method, it becomes a mess. If you want to reorder them or make some optional, it’s hard.

The Solution: The Chain of Responsibility

The Chain of Responsibility Pattern 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.

Real-Life Analogy: Tech Support 📞

  1. Level 1 Support: “Have you tried restarting?” (Can’t fix? Pass to L2).
  2. Level 2 Support: “Is it plugged in?” (Can’t fix? Pass to L3).
  3. Level 3 Support: “It’s a bug. We’ll fix it.”

The user doesn’t care who fixes it, just that it gets fixed.

Visualizing the Pattern

Chain of Responsibility Pattern

Implementation

1. The Handler Abstract Class

public abstract class SupportHandler {
    private SupportHandler next;

    public SupportHandler setNext(SupportHandler next) {
        this.next = next;
        return next; // Returning next allows chaining: h1.setNext(h2).setNext(h3)
    }

    public void handleRequest(String issue) {
        if (canHandle(issue)) {
            resolve(issue);
        } else if (next != null) {
            next.handleRequest(issue); // Pass it down
        } else {
            System.out.println("Ticket Unresolved: " + issue);
        }
    }

    protected abstract boolean canHandle(String issue);
    protected abstract void resolve(String issue);
}

2. Concrete Handlers

public class Level1Support extends SupportHandler {
    @Override
    protected boolean canHandle(String issue) {
        return issue.equals("basic");
    }

    @Override
    protected void resolve(String issue) {
        System.out.println("Level 1 fixed: Turned it off and on again.");
    }
}

public class Level2Support extends SupportHandler {
    @Override
    protected boolean canHandle(String issue) {
        return issue.equals("advanced");
    }

    @Override
    protected void resolve(String issue) {
        System.out.println("Level 2 fixed: Reinstalled drivers.");
    }
}

Usage

SupportHandler l1 = new Level1Support();
SupportHandler l2 = new Level2Support();

// Build the chain
l1.setNext(l2);

// Send requests
l1.handleRequest("basic"); 
// Output: Level 1 fixed...

l1.handleRequest("advanced"); 
// Output: Level 2 fixed... (L1 passed it to L2)

l1.handleRequest("impossible"); 
// Output: Ticket Unresolved

In The Wild (Real World Examples)

1. Servlet Filters / Spring Security Filter Chain

When an HTTP request hits your server, it goes through a chain: CorsFilter -> AuthFilter -> LoggingFilter -> YourController. Each filter works and passes it to chain.doFilter().

2. Exception Handling (try-catch)

When an exception is thrown, the JVM looks for a catch block in the current method. If not found, it goes to the caller (Next Handler). This bubbles up the stack until caught.

Cheat Sheet

FeatureDetails
CategoryBehavioral
Problem SolvedDecoupling sender from receiver, sequential processing
Key implementationLinked List of objects (nextHandler)
ProsDynamic (Change chain order at runtime), Single Responsibility
ConsPerformance (Long chains can be slow), Guarantee (Request might fall off the end unhandled)

Tips to Remember 🧠

  • “The Bucket Brigade”: Like passing a bucket of water to put out a fire.
  • Middleware: Almost all web middleware (Express.js, Django, Spring) uses this pattern.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.