Fundamentals 12 min read

Mastering the Chain of Responsibility Pattern: From Flawed IF Chains to Elegant Handlers

This article explains the Chain of Responsibility design pattern, shows why naïve nested if‑statements are problematic, demonstrates a step‑by‑step refactor using linked handlers, introduces an abstract handler hierarchy, and finally presents a factory‑based dynamic configuration for scalable request processing in Java.

Programmer DD
Programmer DD
Programmer DD
Mastering the Chain of Responsibility Pattern: From Flawed IF Chains to Elegant Handlers

Background

The author describes a recent experience where a team member implemented an import feature using the Chain of Responsibility pattern, resulting in overly complex code with many bugs, and argues that a Template Method would have been more appropriate.

What Is the Chain of Responsibility?

The Chain of Responsibility is a behavioral design pattern that lets you pass a request along a chain of handlers; each handler can either process the request or forward it to the next handler.

Usage Scenarios

Multi‑condition flow control such as permission checks

ERP workflow approvals (e.g., manager, HR manager, project manager)

Underlying implementation of Java filters

Bad Example (Nested IFs)

A game with three levels is implemented using nested if‑statements, which quickly becomes unreadable and hard to maintain as the number of levels grows.

public class FirstPassHandler {
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        return 80;
    }
}
public class SecondPassHandler {
    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        return 90;
    }
}
public class ThirdPassHandler {
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");
        return 95;
    }
}
public class HandlerClient {
    public static void main(String[] args){
        FirstPassHandler first = new FirstPassHandler();
        SecondPassHandler second = new SecondPassHandler();
        ThirdPassHandler third = new ThirdPassHandler();
        int firstScore = first.handler();
        if(firstScore >= 80){
            int secondScore = second.handler();
            if(secondScore >= 90){
                third.handler();
            }
        }
    }
}

When the number of levels increases to 100, the code becomes a deep cascade of if‑statements, making maintenance risky.

Initial Refactor

By linking each level as a node in a chain, the client no longer needs multiple if‑checks. Each handler holds a reference to the next handler and forwards the request when appropriate.

public class FirstPassHandler {
    private SecondPassHandler secondPassHandler;
    public void setSecondPassHandler(SecondPassHandler h){ this.secondPassHandler = h; }
    private int play(){ return 80; }
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        if(play() >= 80 && secondPassHandler != null){
            return secondPassHandler.handler();
        }
        return 80;
    }
}
// Similar implementations for SecondPassHandler and ThirdPassHandler
public class HandlerClient {
    public static void main(String[] args){
        FirstPassHandler first = new FirstPassHandler();
        SecondPassHandler second = new SecondPassHandler();
        ThirdPassHandler third = new ThirdPassHandler();
        first.setSecondPassHandler(second);
        second.setThirdPassHandler(third);
        first.handler();
    }
}

Drawbacks of the Initial Refactor

Each concrete handler must declare a different type for its next handler, making the chain hard to extend.

The code’s extensibility is poor.

Improved Chain Refactor

Introduce an abstract handler that defines a generic next reference, allowing all concrete handlers to share the same base type.

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("第一关-->FirstPassHandler");
        int score = play();
        if(score >= 80 && next != null){
            return next.handler();
        }
        return score;
    }
}
// SecondPassHandler and ThirdPassHandler extend AbstractHandler similarly
public class HandlerClient {
    public static void main(String[] args){
        FirstPassHandler first = new FirstPassHandler();
        SecondPassHandler second = new SecondPassHandler();
        ThirdPassHandler third = new ThirdPassHandler();
        first.setNext(second);
        second.setNext(third);
        first.handler();
    }
}

Factory‑Based Dynamic Chain Construction

Use an enum to describe each handler’s configuration (id, name, class name, previous and next ids). A factory reads the enum, creates handler instances via reflection, and links them automatically.

public enum GatewayEnum {
    API_HANDLER(new GatewayEntity(1,"api接口限流","cn.dgut.design.chain_of_responsibility.GateWay.impl.ApiLimitGatewayHandler",null,2)),
    BLACKLIST_HANDLER(new GatewayEntity(2,"黑名单拦截","cn.dgut.design.chain_of_responsibility.GateWay.impl.BlacklistGatewayHandler",1,3)),
    SESSION_HANDLER(new GatewayEntity(3,"用户会话拦截","cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler",2,null));
    private GatewayEntity gatewayEntity;
    GatewayEnum(GatewayEntity e){ this.gatewayEntity = e; }
    public GatewayEntity getGatewayEntity(){ return gatewayEntity; }
}
// GatewayDao, GatewayImpl, GatewayHandlerEnumFactory, and GetewayClient classes follow the same logic as described in the source.

Conclusion

The Chain of Responsibility is one of many design patterns; mastering it helps write cleaner, more maintainable code. Design patterns are an art that requires continuous learning and practice.

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 ResponsibilitySoftware Architecturedesign patternrefactoring
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.