How the Chain of Responsibility Pattern Simplifies Java Import Logic

This article explains the Chain of Responsibility design pattern, shows why a naïve nested‑if implementation is problematic, and demonstrates step‑by‑step refactorings—including abstract handlers and a factory‑based configuration—to create clean, maintainable Java backend code.

Java Backend Technology
Java Backend Technology
Java Backend Technology
How the Chain of Responsibility Pattern Simplifies Java Import Logic

Background

Recently I asked a team member to implement an import feature using the Chain of Responsibility pattern, but the code became overly complex and buggy. In fact, the Template Method pattern would have been more appropriate, so we performed a collective code review.

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.

Use Cases

Multi‑condition flow control such as permission checks

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

Underlying implementation of Java filters

Anti‑example

Consider a game where advancing to the next level requires the previous level’s score to exceed a threshold. A naïve implementation uses nested if statements for each level, leading to repetitive and hard‑to‑maintain code.

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();
            }
        }
    }
}

If the game had 100 levels, the code would become a deep cascade of if statements, making maintenance risky.

Initial Refactor

Link each level with a linked‑list style chain so the client no longer needs multiple if checks.

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

Each concrete handler holds a reference to a specific next handler, making the chain hard to modify.

Extension and reuse are poor.

Chain Refactor with Abstract Handler

Introduce an abstract handler that defines a next reference and an abstract handler() method. Concrete handlers extend this class.

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 are similar
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 Chain Construction

Use an enum or configuration file to describe the chain. The factory builds the chain dynamically via reflection.

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));
    // getters and constructor omitted
}
public class GatewayHandlerEnumFactory{
    private static GatewayDao gatewayDao = new GatewayImpl();
    public static GatewayHandler getFirstGatewayHandler(){
        GatewayEntity first = gatewayDao.getFirstGatewayEntity();
        GatewayHandler firstHandler = newGatewayHandler(first);
        GatewayEntity cur = first;
        GatewayHandler curHandler = firstHandler;
        while(cur.getNextHandlerId() != null){
            GatewayEntity next = gatewayDao.getGatewayEntity(cur.getNextHandlerId());
            GatewayHandler nextHandler = newGatewayHandler(next);
            curHandler.setNext(nextHandler);
            curHandler = nextHandler;
            cur = next;
        }
        return firstHandler;
    }
    private static GatewayHandler newGatewayHandler(GatewayEntity entity){
        try{
            Class<?> clazz = Class.forName(entity.getConference());
            return (GatewayHandler) clazz.newInstance();
        }catch(Exception e){ e.printStackTrace(); }
        return null;
    }
}

Conclusion

Design patterns are an art; the Chain of Responsibility is just one useful pattern among many, and mastering it can greatly improve code maintainability.

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.

BackendChain of ResponsibilityDesign Patternsrefactoring
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.