责任链模式(Chain of Responsibility Pattern)
一、模式概述
责任链模式是一种行为型设计模式,它为请求创建了一个处理者对象的链。每个处理者包含对下一个处理者的引用,请求沿着链传递,直到某个处理者处理它为止。
核心思想:将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
二、角色说明
| 角色 | 说明 |
|---|---|
| Handler(抽象处理者) | 定义处理请求的接口,包含对下一个处理者的引用 |
| ConcreteHandler(具体处理者) | 实现处理请求的逻辑,决定是处理还是传递给下一个处理者 |
| Client(客户端) | 创建处理者链,发送请求 |
三、生活中的例子
- 审批流程:员工请假 -> 组长审批 -> 经理审批 -> 总监审批 -> CEO审批
- Servlet Filter:请求经过多个过滤器(编码、认证、日志等)
- 异常处理:异常沿着调用栈向上传播,直到被某个 catch 捕获
- DOM 事件冒泡:点击事件从最内层元素向外层传播
四、示例1:审批工作流系统
问题场景
公司请假审批流程:不同天数的请假需要不同级别的领导审批。
java
// ========== 抽象处理者 ==========
/**
* 审批处理者(抽象类)
* 定义了审批链的结构和通用逻辑
*/
abstract class ApprovalHandler {
protected ApprovalHandler nextHandler; // 下一个处理者
protected String name;
protected String position;
protected int maxLeaveDays; // 最大可审批天数
public ApprovalHandler(String name, String position, int maxLeaveDays) {
this.name = name;
this.position = position;
this.maxLeaveDays = maxLeaveDays;
}
/**
* 设置下一个处理者(支持链式调用)
*/
public ApprovalHandler setNext(ApprovalHandler next) {
this.nextHandler = next;
return next; // 返回下一个处理者,方便链式设置
}
/**
* 处理审批请求
*/
public final void handleRequest(LeaveRequest request) {
if (canHandle(request)) {
process(request);
} else {
System.out.println("[" + position + " " + name + "] "
+ "无权审批 " + request.getDays() + " 天请假,转交上级...");
if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("[系统] 没有更高权限的审批人,申请被拒绝!");
}
}
}
/**
* 判断是否有权限处理该请求
*/
protected boolean canHandle(LeaveRequest request) {
return request.getDays() <= maxLeaveDays;
}
/**
* 具体的审批逻辑(由子类实现)
*/
protected abstract void process(LeaveRequest request);
}
// ========== 具体处理者 ==========
/**
* 组长:最多可审批3天
*/
class TeamLeader extends ApprovalHandler {
public TeamLeader(String name) {
super(name, "组长", 3);
}
@Override
protected void process(LeaveRequest request) {
System.out.println("[组长 " + name + "] 审批通过!"
+ " " + request.getEmployee() + " 请假 " + request.getDays()
+ " 天,原因: " + request.getReason());
}
}
/**
* 经理:最多可审批7天
*/
class Manager extends ApprovalHandler {
public Manager(String name) {
super(name, "经理", 7);
}
@Override
protected void process(LeaveRequest request) {
if (request.getDays() > 3) {
System.out.println("[经理 " + name + "] 审批通过!"
+ " " + request.getEmployee() + " 请假 " + request.getDays()
+ " 天,原因: " + request.getReason());
} else {
// 经理也可以处理3天以下的,但通常不处理
System.out.println("[经理 " + name + "] 审批通过!"
+ " " + request.getEmployee() + " 请假 " + request.getDays()
+ " 天,原因: " + request.getReason());
}
}
}
/**
* 总监:最多可审批15天
*/
class Director extends ApprovalHandler {
public Director(String name) {
super(name, "总监", 15);
}
@Override
protected void process(LeaveRequest request) {
System.out.println("[总监 " + name + "] 审批通过!"
+ " " + request.getEmployee() + " 请假 " + request.getDays()
+ " 天,原因: " + request.getReason());
}
}
/**
* CEO:无限制
*/
class CEO extends ApprovalHandler {
public CEO(String name) {
super(name, "CEO", Integer.MAX_VALUE);
}
@Override
protected void process(LeaveRequest request) {
System.out.println("[CEO " + name + "] 审批通过!"
+ " " + request.getEmployee() + " 请假 " + request.getDays()
+ " 天,原因: " + request.getReason());
}
}
// ========== 请假请求 ==========
/**
* 请假请求
*/
class LeaveRequest {
private String employee; // 请假人
private int days; // 请假天数
private String reason; // 请假原因
public LeaveRequest(String employee, int days, String reason) {
this.employee = employee;
this.days = days;
this.reason = reason;
}
public String getEmployee() { return employee; }
public int getDays() { return days; }
public String getReason() { return reason; }
}
// ========== 客户端代码 ==========
public class ApprovalChainDemo {
public static void main(String[] args) {
// 创建审批链:组长 -> 经理 -> 总监 -> CEO
ApprovalHandler teamLeader = new TeamLeader("王组长");
ApprovalHandler manager = new Manager("李经理");
ApprovalHandler director = new Director("张总监");
ApprovalHandler ceo = new CEO("刘CEO");
teamLeader.setNext(manager)
.setNext(director)
.setNext(ceo);
System.out.println("===== 请假2天 =====");
teamLeader.handleRequest(new LeaveRequest("小明", 2, "感冒发烧"));
System.out.println("\n===== 请假5天 =====");
teamLeader.handleRequest(new LeaveRequest("小红", 5, "回家探亲"));
System.out.println("\n===== 请假10天 =====");
teamLeader.handleRequest(new LeaveRequest("小刚", 10, "出国旅游"));
System.out.println("\n===== 请假30天 =====");
teamLeader.handleRequest(new LeaveRequest("小李", 30, "结婚"));
}
}运行结果
===== 请假2天 =====
[组长 王组长] 审批通过! 小明 请假 2 天,原因: 感冒发烧
===== 请假5天 =====
[组长 王组长] 无权审批 5 天请假,转交上级...
[经理 李经理] 审批通过! 小红 请假 5 天,原因: 回家探亲
===== 请假10天 =====
[组长 王组长] 无权审批 10 天请假,转交上级...
[经理 李经理] 无权审批 10 天请假,转交上级...
[总监 张总监] 审批通过! 小刚 请假 10 天,原因: 出国旅游
===== 请假30天 =====
[组长 王组长] 无权审批 30 天请假,转交上级...
[经理 李经理] 无权审批 30 天请假,转交上级...
[总监 张总监] 无权审批 30 天请假,转交上级...
[CEO 刘CEO] 审批通过! 小李 请假 30 天,原因: 结婚五、示例2:Servlet Filter 链
模拟 Servlet Filter 的工作原理
java
import java.util.ArrayList;
import java.util.List;
// ========== Filter 接口 ==========
/**
* 模拟 Servlet Filter 接口
*/
interface WebFilter {
String getName();
void doFilter(FilterRequest request, FilterChain chain);
}
/**
* 过滤器链
*/
class FilterChain {
private final List<WebFilter> filters = new ArrayList<>();
private int index = 0;
public FilterChain addFilter(WebFilter filter) {
filters.add(filter);
return this;
}
/**
* 执行过滤器链
*/
public void doFilter(FilterRequest request) {
if (index < filters.size()) {
WebFilter filter = filters.get(index++);
System.out.println(" [Filter] 进入: " + filter.getName());
filter.doFilter(request, this);
System.out.println(" [Filter] 退出: " + filter.getName());
} else {
System.out.println(" [Filter] 所有过滤器执行完毕,处理请求...");
}
}
}
/**
* 过滤器请求
*/
class FilterRequest {
private String url;
private String method;
private String contentType;
private String authToken;
private java.util.Map<String, String> headers = new java.util.HashMap<>();
public FilterRequest(String url, String method) {
this.url = url;
this.method = method;
}
public String getUrl() { return url; }
public String getMethod() { return method; }
public String getContentType() { return contentType; }
public void setContentType(String type) { this.contentType = type; }
public String getAuthToken() { return authToken; }
public void setAuthToken(String token) { this.authToken = token; }
public java.util.Map<String, String> getHeaders() { return headers; }
}
// ========== 具体过滤器 ==========
/**
* 编码过滤器:设置字符编码
*/
class EncodingFilter implements WebFilter {
@Override
public String getName() { return "EncodingFilter"; }
@Override
public void doFilter(FilterRequest request, FilterChain chain) {
System.out.println(" [编码过滤器] 设置 UTF-8 编码");
request.setContentType("text/html;charset=UTF-8");
chain.doFilter(request); // 继续下一个过滤器
}
}
/**
* 日志过滤器:记录请求日志
*/
class LoggingFilter implements WebFilter {
@Override
public String getName() { return "LoggingFilter"; }
@Override
public void doFilter(FilterRequest request, FilterChain chain) {
long start = System.currentTimeMillis();
System.out.println(" [日志过滤器] 请求: " + request.getMethod()
+ " " + request.getUrl());
chain.doFilter(request); // 继续下一个过滤器
long cost = System.currentTimeMillis() - start;
System.out.println(" [日志过滤器] 响应时间: " + cost + "ms");
}
}
/**
* 认证过滤器:检查登录状态
*/
class AuthFilter implements WebFilter {
@Override
public String getName() { return "AuthFilter"; }
@Override
public void doFilter(FilterRequest request, FilterChain chain) {
String token = request.getAuthToken();
if (token == null || token.isEmpty()) {
System.out.println(" [认证过滤器] 未登录,拒绝访问!");
return; // 不调用 chain.doFilter,请求到此为止
}
System.out.println(" [认证过滤器] Token验证通过");
chain.doFilter(request); // 继续下一个过滤器
}
}
/**
* CORS 过滤器:处理跨域请求
*/
class CorsFilter implements WebFilter {
@Override
public String getName() { return "CorsFilter"; }
@Override
public void doFilter(FilterRequest request, FilterChain chain) {
System.out.println(" [CORS过滤器] 添加跨域头: Access-Control-Allow-Origin: *");
request.getHeaders().put("Access-Control-Allow-Origin", "*");
chain.doFilter(request);
}
}
// ========== 客户端代码 ==========
public class FilterChainDemo {
public static void main(String[] args) {
// 构建过滤器链
FilterChain chain = new FilterChain();
chain.addFilter(new LoggingFilter())
.addFilter(new EncodingFilter())
.addFilter(new AuthFilter())
.addFilter(new CorsFilter());
// 模拟请求1:已登录
System.out.println("===== 请求1:已登录用户访问 /api/users =====");
FilterRequest request1 = new FilterRequest("/api/users", "GET");
request1.setAuthToken("abc123");
chain.doFilter(request1);
System.out.println();
// 模拟请求2:未登录
System.out.println("===== 请求2:未登录用户访问 /api/orders =====");
FilterChain chain2 = new FilterChain(); // 需要新建链(index已重置)
chain2.addFilter(new LoggingFilter())
.addFilter(new EncodingFilter())
.addFilter(new AuthFilter())
.addFilter(new CorsFilter());
FilterRequest request2 = new FilterRequest("/api/orders", "POST");
chain2.doFilter(request2);
}
}六、示例3:支持动态添加处理器的责任链
java
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
/**
* 可动态构建的责任链(使用函数式接口)
*/
class DynamicChain<T> {
private final List<ChainHandler<T>> handlers = new ArrayList<>();
/**
* 添加处理器
*/
public DynamicChain<T> addHandler(Predicate<T> condition, java.util.function.Consumer<T> action) {
handlers.add(new ChainHandler<>(condition, action));
return this;
}
/**
* 执行责任链
* 如果某个处理器处理了请求(返回true),则停止传递
*/
public void process(T request) {
for (ChainHandler<T> handler : handlers) {
if (handler.condition.test(request)) {
handler.action.accept(request);
return; // 已处理,停止传递
}
}
System.out.println(" [系统] 没有处理器能处理此请求");
}
private static class ChainHandler<T> {
Predicate<T> condition;
java.util.function.Consumer<T> action;
ChainHandler(Predicate<T> condition, java.util.function.Consumer<T> action) {
this.condition = condition;
this.action = action;
}
}
}
/**
* 支付请求
*/
class PaymentRequest {
double amount;
String type; // "alipay", "wechat", "bank"
public PaymentRequest(double amount, String type) {
this.amount = amount;
this.type = type;
}
}
// ========== 客户端代码 ==========
public class DynamicChainDemo {
public static void main(String[] args) {
DynamicChain<PaymentRequest> paymentChain = new DynamicChain<>();
paymentChain
.addHandler(r -> r.type.equals("alipay") && r.amount <= 5000,
r -> System.out.println(" [支付宝] 处理 " + r.amount + " 元支付"))
.addHandler(r -> r.type.equals("alipay"),
r -> System.out.println(" [支付宝-大额] 处理 " + r.amount + " 元大额支付"))
.addHandler(r -> r.type.equals("wechat"),
r -> System.out.println(" [微信支付] 处理 " + r.amount + " 元支付"))
.addHandler(r -> r.type.equals("bank"),
r -> System.out.println(" [银行转账] 处理 " + r.amount + " 元支付"));
System.out.println("===== 支付宝小额支付 =====");
paymentChain.process(new PaymentRequest(100, "alipay"));
System.out.println("\n===== 支付宝大额支付 =====");
paymentChain.process(new PaymentRequest(10000, "alipay"));
System.out.println("\n===== 微信支付 =====");
paymentChain.process(new PaymentRequest(200, "wechat"));
System.out.println("\n===== 银行转账 =====");
paymentChain.process(new PaymentRequest(50000, "bank"));
}
}七、UML 类图
┌──────────────┐
│ Client │───创建──▶ Handler Chain
└──────────────┘
│
▼
┌──────────────────────────┐
│ Handler (抽象处理者) │
│ - nextHandler: Handler │
│ + handleRequest() │
└──────────┬───────────────┘
│ 继承
┌──────┴──────┐
│ │
┌───┴────┐ ┌───┴────┐ ┌──────────┐
│Concrete│ │Concrete│ │Concrete │
│Handler1│ │Handler2│ │Handler3 │
│process()│ │process()│ │process()│
└────────┘ └────────┘ └──────────┘
│ │ │
└────next─────┘────next────┘八、优缺点分析
优点
- 解耦:发送者不需要知道请求由哪个处理者处理
- 单一职责:每个处理者只关注自己的处理逻辑
- 灵活性强:可以动态调整处理者的顺序或增删处理者
- 符合开闭原则:新增处理者不需要修改现有代码
缺点
- 不能保证一定被处理:如果链上没有处理者能处理,请求可能丢失
- 链过长影响性能:请求可能需要经过很多处理者才能被处理
- 调试困难:请求在链中传递,调试时不容易跟踪
- 循环引用:如果链设置不当,可能造成无限循环
九、使用场景
- Web 框架:Servlet Filter、Spring Interceptor、Netty ChannelPipeline
- 审批流程:OA系统中的多级审批
- 异常处理:异常沿着调用栈传播
- 中间件:日志、认证、限流等中间件
- 事件处理:GUI事件的冒泡机制
- Java 异常处理:try-catch-finally 链
十、最佳实践
- 确保链有终止条件:避免请求永远不被处理
- 控制链的长度:过长的链会影响性能和可维护性
- 考虑使用责任链+组合模式:处理树形结构的请求
- 注意性能:每个处理者都可能执行,考虑缓存机制
- 合理设置处理顺序:通用的处理者放在前面,特殊的放在后面
总结:责任链模式将请求的发送者和接收者解耦,让多个对象都有机会处理请求。在实际应用中,Servlet Filter、Spring Interceptor、审批流程等都是责任链模式的典型应用。使用时要注意确保链有终止条件,避免请求丢失或无限循环。