什么是责任链模式?应用场景有哪些?
2026年01月25日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,主要希望考察以下几个层面:
- 对设计模式的基本理解:你是否能清晰、准确地阐述一种经典设计模式的定义和核心思想。
- 对模式结构和运行机制的掌握:你能否描述出该模式的关键角色(如
Handler、ConcreteHandler)以及它们之间如何协作,构成“链”并传递请求。 - 理论与实践结合的能力:这往往是面试官不仅仅想知道理论,更是想知道你是否能在实际开发中识别并应用该模式。列举的应用场景是否典型、合理,能否说明使用该模式带来的好处(如解耦、灵活性)。
- 对模式优劣和细节的认知:你是否了解责任链模式的优缺点,以及在实现时需要注意的常见陷阱(例如,保证链的完整性、处理默认行为等)。
核心答案
责任链模式 是一种行为型设计模式。它允许多个对象(处理器)都有机会处理同一个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。核心目的在于将请求的发送者与接收者解耦,让多个接收对象都有机会处理请求,同时也可以动态地修改处理链。
典型的应用场景包括:
- 多级请求处理:如员工请假、费用报销审批流程(需经组长、经理、总监等多级审批)。
- 过滤器和拦截器:Servlet 中的
FilterChain、Spring MVC 的HandlerInterceptor。 - 日志记录器:不同级别的日志(DEBUG、INFO、ERROR)被不同记录器处理。
- 异常处理:某些框架中,异常会在一系列处理器中传递,寻找能处理该异常类型的处理器。
深度解析
原理/机制
该模式的核心是建立一个处理器链。每个处理器都包含一个对下一个处理器的引用。当一个请求到来时,处理器先判断自己能否处理。如果能,则处理并结束;如果不能(或处理完后选择继续传递),则将请求转发给链中的下一个处理器。
关键角色:
- 抽象处理器(Handler):定义处理请求的接口(或抽象类),通常包含一个处理请求的方法(如
handleRequest)和一个设置下一个处理器的属性(如successor)。 - 具体处理器(ConcreteHandler):实现抽象处理器的接口,负责处理它所能负责的请求。如果可以处理,则处理;否则,将请求转发给后继者。
- 客户端(Client):负责组装责任链,并将请求提交给链上的第一个处理器。
代码示例
以下是一个简化的请假审批流程示例:
// 1. 抽象处理器
abstract class Approver {
protected Approver nextApprover; // 持有下一个处理者的引用
protected String name;
public Approver(String name) {
this.name = name;
}
// 设置下一个处理者(用于构建链)
public Approver setNext(Approver nextApprover) {
this.nextApprover = nextApprover;
return this.nextApprover; // 支持链式调用,方便构建
}
// 处理请求的核心方法
public abstract void processRequest(LeaveRequest request);
}
// 2. 具体处理器:小组长
class GroupLeader extends Approver {
public GroupLeader(String name) { super(name); }
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 2) {
System.out.println(name + "(组长)审批了" + request.getName() + "的请假,天数为:" + request.getDays());
} else if (nextApprover != null) {
System.out.println(name + "(组长)无权审批,转交上级。");
nextApprover.processRequest(request); // 传递给下一级
} else {
System.out.println("链已结束,无人能处理该请求。");
}
}
}
// 2. 具体处理器:部门经理
class Manager extends Approver {
public Manager(String name) { super(name); }
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println(name + "(经理)审批了" + request.getName() + "的请假,天数为:" + request.getDays());
} else if (nextApprover != null) {
System.out.println(name + "(经理)无权审批,转交上级。");
nextApprover.processRequest(request);
}
}
}
// 请求类
class LeaveRequest {
private String name;
private int days;
// 省略构造方法和getter/setter
}
// 3. 客户端(组装链并提交请求)
public class Client {
public static void main(String[] args) {
// 构建责任链: GroupLeader -> Manager (还可以继续追加总监等)
Approver groupLeader = new GroupLeader("张组长");
Approver manager = new Manager("李经理");
groupLeader.setNext(manager); // 设置链关系
// 提交不同请求
LeaveRequest request1 = new LeaveRequest("小王", 1);
LeaveRequest request2 = new LeaveRequest("老李", 5);
LeaveRequest request3 = new LeaveRequest("大刘", 10);
groupLeader.processRequest(request1); // 张组长处理
groupLeader.processRequest(request2); // 张组长转交李经理处理
groupLeader.processRequest(request3); // 层层转交,本例中链末端,无人处理
}
}
对比分析与注意事项
- 与装饰器模式的区别:两者结构相似(都包含对同类对象的引用),但目的不同。责任链模式的各个处理器是 “互斥” 的,一个请求通常只被一个处理器处理(或无人处理),核心是传递与选择。装饰器模式的各个装饰者是 “叠加” 的,所有装饰者都会参与处理,核心是功能增强。
最佳实践与常见误区
- 动态构建链:责任链应在运行时可以灵活配置和修改,这是其核心优势之一。可以通过配置文件、数据库或依赖注入框架(如 Spring)来管理链的组成。
- 确保链的完整性:实现时,务必在处理器末尾进行判空(
if (nextHandler != null)),防止空指针异常,并为无法处理的请求提供默认行为(如记录日志、抛出异常或使用一个 “最终处理器”)。 - 性能考量:如果链过长,且大部分请求需要传递到末端才被处理,可能会影响性能。在设计时,可以将最可能被处理的处理器放在链的前端,或根据请求特征进行智能路由(但这会增加复杂性)。
- 常见误区:在具体处理器中忘记调用下一个处理器(
nextHandler.handle(request)),导致责任链断裂,请求无法继续传递。
总结
责任链模式通过构建一条处理器链,将请求的发送与具体处理解耦,提供了灵活扩展处理流程的优秀能力,特别适用于多级审批、过滤拦截等场景,但使用时需注意链的完整性和性能。