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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
