Fundamentals 12 min read

Mastering the Chain of Responsibility Pattern: From Flawed Code to Clean Design

This article explains the Chain of Responsibility design pattern, its typical use cases, shows a problematic nested‑if implementation for a game level system, and demonstrates step‑by‑step refactorings—including a linked‑handler chain and an enum‑based factory—to produce maintainable, extensible Java code.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Mastering the Chain of Responsibility Pattern: From Flawed Code to Clean Design

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 of which can either process the request or forward it to the next handler.

Chain of Responsibility diagram
Chain of Responsibility diagram

Usage Scenarios

The pattern is useful in many situations, such as:

Multi‑condition flow control: permission checks

ERP workflow approval: general manager, HR manager, project manager

Underlying implementation of Java servlet filters

Anti‑Example

Consider a simple game where advancing to the next level requires a minimum score from the previous level. The naïve implementation uses nested if statements for each level:

// First level
public class FirstPassHandler {
    public int handler() {
        System.out.println("第一关-->FirstPassHandler");
        return 80;
    }
}

// Second level
public class SecondPassHandler {
    public int handler() {
        System.out.println("第二关-->SecondPassHandler");
        return 90;
    }
}

// Third level
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 explode into deeply nested if blocks, making maintenance risky and cumbersome.

if (第1关通过) {
    // 第2关游戏
    if (第2关通过) {
        // 第3关游戏
        if (第3关通过) {
            // ...
        }
    }
}

Initial Refactor

To avoid repetitive condition checks, we can link each level as a handler in a chain. The client only invokes the first handler:

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

public class SecondPassHandler extends AbstractHandler {
    private int play() { return 90; }
    @Override
    public int handler() {
        System.out.println("第二关-->SecondPassHandler");
        int score = play();
        if (score >= 90 && next != null) {
            return next.handler();
        }
        return score;
    }
}

public class ThirdPassHandler extends AbstractHandler {
    private int play() { return 95; }
    @Override
    public int handler() {
        System.out.println("第三关-->ThirdPassHandler");
        return play();
    }
}

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

Chain Factory Refactor

We can externalize the chain configuration into an enum and build the chain dynamically via a factory:

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));
    GatewayEntity gatewayEntity;
    GatewayEnum(GatewayEntity gatewayEntity) { this.gatewayEntity = gatewayEntity; }
    public GatewayEntity getGatewayEntity() { return gatewayEntity; }
}

public class GatewayHandlerEnumFactory {
    private static GatewayDao gatewayDao = new GatewayImpl();
    public static GatewayHandler getFirstGatewayHandler() {
        GatewayEntity firstEntity = gatewayDao.getFirstGatewayEntity();
        GatewayHandler firstHandler = newGatewayHandler(firstEntity);
        GatewayEntity curEntity = firstEntity;
        GatewayHandler curHandler = firstHandler;
        Integer nextId;
        while ((nextId = curEntity.getNextHandlerId()) != null) {
            GatewayEntity nextEntity = gatewayDao.getGatewayEntity(nextId);
            GatewayHandler nextHandler = newGatewayHandler(nextEntity);
            curHandler.setNext(nextHandler);
            curHandler = nextHandler;
            curEntity = nextEntity;
        }
        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;
    }
}
Factory diagram
Factory diagram

Conclusion

Design patterns are numerous; the Chain of Responsibility is a powerful example that promotes clean, extensible code. Mastering such patterns is essential for building maintainable software architectures.

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
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.