Fundamentals 10 min read

Understanding and Refactoring the Chain of Responsibility Design Pattern in Java

This article explains the Chain of Responsibility design pattern, its typical use cases, shows an anti‑example of overly nested conditional code, and demonstrates step‑by‑step refactoring—including an abstract handler, concrete handlers, and a factory‑based configuration—to achieve cleaner, more maintainable Java implementations.

Architect
Architect
Architect
Understanding and Refactoring the Chain of Responsibility Design Pattern in Java

Background : The author attempted to implement an import feature using the Chain of Responsibility pattern, resulting in overly complex and buggy code, and notes that the Template Method would have been a better fit.

What is Chain of Responsibility : A behavioral design pattern that allows a request to travel along a chain of handlers, each deciding whether to process the request or pass it to the next handler.

Usage Scenarios : Multi‑condition flow control (e.g., permission checks), ERP approval processes, Java servlet filters, etc.

Anti‑example : A simple game with three levels implemented using nested if statements, illustrating code bloat and maintenance difficulty when the number of levels grows.

Initial Refactor : Shows a naive chain where each level holds a reference to the next, still cumbersome due to duplicated code and explicit client wiring.

Improved Refactor : Introduces an abstract handler with a next reference and concrete handlers overriding handler(). The client only needs to set the chain, dramatically reducing duplication.

public abstract class AbstractHandler {
    protected AbstractHandler next;
    public void setNext(AbstractHandler next) { this.next = next; }
    public abstract int handler();
}

public class FirstPassHandler extends AbstractHandler {
    private int play() { return 80; }
    @Override
    public int handler() {
        System.out.println("First level");
        int score = play();
        if (score >= 80 && next != null) {
            return next.handler();
        }
        return score;
    }
}

Factory Enhancement : Demonstrates building the chain from an enum or configuration file using reflection, allowing dynamic assembly of handlers without hard‑coding dependencies.

public static GatewayHandler getFirstGatewayHandler() {
    GatewayEntity first = gatewayDao.getFirstGatewayEntity();
    GatewayHandler handler = newGatewayHandler(first);
    // iterate and link subsequent handlers based on configuration
    return handler;
}

Conclusion : The Chain of Responsibility is a powerful pattern when applied appropriately, but overusing it can lead to unnecessary complexity; careful design and refactoring can keep the code clean and extensible.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Chain of ResponsibilityDesign PatternsJavarefactoring
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.