责任链模式详解
在实际的软件开发中,我们经常会遇到这样的场景:一个请求需要经过多个处理者的处理,但我们不希望请求的发送者与接收者耦合在一起。责任链模式(Chain of Responsibility Pattern)正是为了解决这类问题而诞生的。本文将深入讲解责任链模式的原理、实现方式以及在生产环境中的实际应用。责任链模式是一种行为型设计模式,它允许你将请求沿着处理者链进行传递,直到其中一个处理者对其进行处理。该
前言
在实际的软件开发中,我们经常会遇到这样的场景:一个请求需要经过多个处理者的处理,但我们不希望请求的发送者与接收者耦合在一起。责任链模式(Chain of Responsibility Pattern)正是为了解决这类问题而诞生的。本文将深入讲解责任链模式的原理、实现方式以及在生产环境中的实际应用。
一、什么是责任链模式
1.1 定义
责任链模式是一种行为型设计模式,它允许你将请求沿着处理者链进行传递,直到其中一个处理者对其进行处理。该模式将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。
1.2 核心思想
责任链模式的核心思想是:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
1.3 模式结构(ASCII图)
┌─────────────┐
│ Client │
└──────┬──────┘
│
│ request
▼
┌─────────────────┐
│ Handler │◄──────────┐
├─────────────────┤ │
│+ setNext() │ │
│+ handleRequest()│ │
└────────┬────────┘ │
│ │
│ │
┌────┴────────┐ │
│ │ │
▼ ▼ │
┌─────────┐ ┌─────────┐ │
│Handler1 │ │Handler2 │ │
├─────────┤ ├─────────┤ │
│handle() │ │handle() │ │
└─────────┘ └─────────┘ │
│ │
└────────────────────────┘
next handler
1.4 角色说明
- Handler(抽象处理者):定义一个处理请求的接口,包含一个指向下一个处理者的引用
- ConcreteHandler(具体处理者):实现抽象处理者的处理方法,判断能否处理请求,如果可以则处理,否则转发给下一个处理者
- Client(客户端):创建并组装责任链,向链上的第一个处理者发送请求
二、责任链模式的实现
2.1 基础实现
首先,我们来看一个简单的责任链模式实现:
/**
* 抽象处理者
*/
public abstract class Handler {
protected Handler nextHandler;
/**
* 设置下一个处理者
*/
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
/**
* 处理请求的抽象方法
*/
public abstract void handleRequest(String request);
}
/**
* 具体处理者A
*/
public class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
if (request.equals("A")) {
System.out.println("ConcreteHandlerA 处理请求: " + request);
} else if (nextHandler != null) {
// 传递给下一个处理者
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理该请求");
}
}
}
/**
* 具体处理者B
*/
public class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
if (request.equals("B")) {
System.out.println("ConcreteHandlerB 处理请求: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理该请求");
}
}
}
/**
* 具体处理者C
*/
public class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(String request) {
if (request.equals("C")) {
System.out.println("ConcreteHandlerC 处理请求: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理该请求");
}
}
}
/**
* 客户端测试
*/
public class Client {
public static void main(String[] args) {
// 创建处理者
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
// 构建责任链: A -> B -> C
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
// 发送请求
System.out.println("发送请求: A");
handlerA.handleRequest("A");
System.out.println("\n发送请求: B");
handlerA.handleRequest("B");
System.out.println("\n发送请求: C");
handlerA.handleRequest("C");
System.out.println("\n发送请求: D");
handlerA.handleRequest("D");
}
}
输出结果:
发送请求: A
ConcreteHandlerA 处理请求: A
发送请求: B
ConcreteHandlerB 处理请求: B
发送请求: C
ConcreteHandlerC 处理请求: C
发送请求: D
没有处理者能够处理该请求
三、生产环境实战案例
3.1 案例一:审批流程系统
在企业管理系统中,不同金额的费用报销需要不同级别的领导审批。这是责任链模式的典型应用场景。
3.1.1 场景分析
审批流程:
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 组长审批 │──▶│ 经理审批 │──▶│ 总监审批 │──▶│ 总经理审批│
│ (≤1000) │ │ (≤5000) │ │ (≤10000) │ │ (>10000) │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
3.1.2 代码实现
/**
* 报销请求类
*/
public class ReimbursementRequest {
private String employeeName; // 员工姓名
private double amount; // 报销金额
private String reason; // 报销理由
public ReimbursementRequest(String employeeName, double amount, String reason) {
this.employeeName = employeeName;
this.amount = amount;
this.reason = reason;
}
public String getEmployeeName() {
return employeeName;
}
public double getAmount() {
return amount;
}
public String getReason() {
return reason;
}
}
/**
* 抽象审批者
*/
public abstract class Approver {
protected Approver nextApprover;
protected String name;
public Approver(String name) {
this.name = name;
}
/**
* 设置下一个审批者
*/
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
/**
* 处理审批请求
*/
public abstract void processRequest(ReimbursementRequest request);
}
/**
* 组长审批者(审批金额≤1000)
*/
public class TeamLeader extends Approver {
public TeamLeader(String name) {
super(name);
}
@Override
public void processRequest(ReimbursementRequest request) {
if (request.getAmount() <= 1000) {
System.out.println("【组长 " + name + " 审批】");
System.out.println("员工:" + request.getEmployeeName());
System.out.println("金额:" + request.getAmount() + " 元");
System.out.println("理由:" + request.getReason());
System.out.println("审批结果:通过");
System.out.println("----------------------------------------");
} else {
System.out.println("【组长 " + name + "】金额超出权限,转交上级审批...");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
/**
* 经理审批者(审批金额≤5000)
*/
public class Manager extends Approver {
public Manager(String name) {
super(name);
}
@Override
public void processRequest(ReimbursementRequest request) {
if (request.getAmount() <= 5000) {
System.out.println("【经理 " + name + " 审批】");
System.out.println("员工:" + request.getEmployeeName());
System.out.println("金额:" + request.getAmount() + " 元");
System.out.println("理由:" + request.getReason());
System.out.println("审批结果:通过");
System.out.println("----------------------------------------");
} else {
System.out.println("【经理 " + name + "】金额超出权限,转交上级审批...");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
/**
* 总监审批者(审批金额≤10000)
*/
public class Director extends Approver {
public Director(String name) {
super(name);
}
@Override
public void processRequest(ReimbursementRequest request) {
if (request.getAmount() <= 10000) {
System.out.println("【总监 " + name + " 审批】");
System.out.println("员工:" + request.getEmployeeName());
System.out.println("金额:" + request.getAmount() + " 元");
System.out.println("理由:" + request.getReason());
System.out.println("审批结果:通过");
System.out.println("----------------------------------------");
} else {
System.out.println("【总监 " + name + "】金额超出权限,转交上级审批...");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
/**
* 总经理审批者(审批所有金额)
*/
public class GeneralManager extends Approver {
public GeneralManager(String name) {
super(name);
}
@Override
public void processRequest(ReimbursementRequest request) {
System.out.println("【总经理 " + name + " 审批】");
System.out.println("员工:" + request.getEmployeeName());
System.out.println("金额:" + request.getAmount() + " 元");
System.out.println("理由:" + request.getReason());
if (request.getAmount() <= 50000) {
System.out.println("审批结果:通过");
} else {
System.out.println("审批结果:金额过大,需要董事会审批");
}
System.out.println("----------------------------------------");
}
}
/**
* 测试客户端
*/
public class ReimbursementTest {
public static void main(String[] args) {
// 创建审批者
Approver teamLeader = new TeamLeader("张三");
Approver manager = new Manager("李四");
Approver director = new Director("王五");
Approver generalManager = new GeneralManager("赵六");
// 构建责任链
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
director.setNextApprover(generalManager);
// 测试不同金额的报销请求
ReimbursementRequest request1 = new ReimbursementRequest(
"小明", 800, "购买办公用品"
);
teamLeader.processRequest(request1);
ReimbursementRequest request2 = new ReimbursementRequest(
"小红", 3500, "参加技术培训"
);
teamLeader.processRequest(request2);
ReimbursementRequest request3 = new ReimbursementRequest(
"小刚", 8000, "采购服务器设备"
);
teamLeader.processRequest(request3);
ReimbursementRequest request4 = new ReimbursementRequest(
"小李", 25000, "市场推广活动"
);
teamLeader.processRequest(request4);
}
}
输出结果:
【组长 张三 审批】
员工:小明
金额:800.0 元
理由:购买办公用品
审批结果:通过
----------------------------------------
【组长 张三】金额超出权限,转交上级审批...
【经理 李四 审批】
员工:小红
金额:3500.0 元
理由:参加技术培训
审批结果:通过
----------------------------------------
【组长 张三】金额超出权限,转交上级审批...
【经理 李四】金额超出权限,转交上级审批...
【总监 王五 审批】
员工:小刚
金额:8000.0 元
理由:采购服务器设备
审批结果:通过
----------------------------------------
【组长 张三】金额超出权限,转交上级审批...
【经理 李四】金额超出权限,转交上级审批...
【总监 王五】金额超出权限,转交上级审批...
【总经理 赵六 审批】
员工:小李
金额:25000.0 元
理由:市场推广活动
审批结果:通过
----------------------------------------
3.2 案例三:敏感词过滤系统
在内容审核系统中,我们需要对用户发布的内容进行多层过滤,这也是责任链模式的实际应用。
3.2.1 过滤链结构
内容过滤链:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 敏感词过滤 │──▶│ HTML过滤 │──▶│ SQL注入过滤 │
└─────────────┘ └─────────────┘ └─────────────┘
3.2.2 代码实现
/**
* 内容请求类
*/
public class ContentRequest {
private String content;
private boolean passed;
private String rejectReason;
public ContentRequest(String content) {
this.content = content;
this.passed = true;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isPassed() {
return passed;
}
public void reject(String reason) {
this.passed = false;
this.rejectReason = reason;
}
public String getRejectReason() {
return rejectReason;
}
}
/**
* 抽象内容过滤器
*/
public abstract class ContentFilter {
protected ContentFilter nextFilter;
public void setNextFilter(ContentFilter nextFilter) {
this.nextFilter = nextFilter;
}
public void filter(ContentRequest request) {
// 执行当前过滤器的过滤逻辑
doFilter(request);
// 如果通过了当前过滤器,且有下一个过滤器,则继续传递
if (request.isPassed() && nextFilter != null) {
nextFilter.filter(request);
}
}
protected abstract void doFilter(ContentRequest request);
}
/**
* 敏感词过滤器
*/
public class SensitiveWordFilter extends ContentFilter {
private static final String[] SENSITIVE_WORDS = {"暴力", "色情", "赌博"};
@Override
protected void doFilter(ContentRequest request) {
String content = request.getContent();
System.out.println("【敏感词过滤器】正在检查内容...");
for (String word : SENSITIVE_WORDS) {
if (content.contains(word)) {
request.reject("内容包含敏感词:" + word);
System.out.println("过滤结果:不通过 - " + request.getRejectReason());
return;
}
}
System.out.println("过滤结果:通过");
}
}
/**
* HTML标签过滤器
*/
public class HtmlTagFilter extends ContentFilter {
@Override
protected void doFilter(ContentRequest request) {
String content = request.getContent();
System.out.println("【HTML标签过滤器】正在检查内容...");
if (content.contains("<script>") || content.contains("</script>")) {
request.reject("内容包含非法HTML标签");
System.out.println("过滤结果:不通过 - " + request.getRejectReason());
return;
}
// 过滤HTML标签
String filtered = content.replaceAll("<[^>]*>", "");
if (!filtered.equals(content)) {
System.out.println("过滤结果:已清理HTML标签");
request.setContent(filtered);
} else {
System.out.println("过滤结果:通过");
}
}
}
/**
* SQL注入过滤器
*/
public class SqlInjectionFilter extends ContentFilter {
private static final String[] SQL_KEYWORDS = {
"select", "insert", "update", "delete", "drop", "union"
};
@Override
protected void doFilter(ContentRequest request) {
String content = request.getContent().toLowerCase();
System.out.println("【SQL注入过滤器】正在检查内容...");
for (String keyword : SQL_KEYWORDS) {
if (content.contains(keyword)) {
request.reject("内容疑似包含SQL注入攻击");
System.out.println("过滤结果:不通过 - " + request.getRejectReason());
return;
}
}
System.out.println("过滤结果:通过");
}
}
/**
* 内容过滤系统测试
*/
public class ContentFilterTest {
private static ContentFilter buildFilterChain() {
ContentFilter sensitiveWordFilter = new SensitiveWordFilter();
ContentFilter htmlTagFilter = new HtmlTagFilter();
ContentFilter sqlInjectionFilter = new SqlInjectionFilter();
// 构建过滤链
sensitiveWordFilter.setNextFilter(htmlTagFilter);
htmlTagFilter.setNextFilter(sqlInjectionFilter);
return sensitiveWordFilter;
}
public static void main(String[] args) {
ContentFilter filterChain = buildFilterChain();
// 测试案例1:正常内容
System.out.println("========== 测试案例1:正常内容 ==========");
ContentRequest request1 = new ContentRequest("这是一条正常的评论内容");
filterChain.filter(request1);
System.out.println("最终结果:" + (request1.isPassed() ? "发布成功" : "发布失败"));
System.out.println();
// 测试案例2:包含敏感词
System.out.println("========== 测试案例2:包含敏感词 ==========");
ContentRequest request2 = new ContentRequest("这条内容包含暴力信息");
filterChain.filter(request2);
System.out.println("最终结果:" + (request2.isPassed() ? "发布成功" : "发布失败"));
System.out.println();
// 测试案例3:包含HTML标签
System.out.println("========== 测试案例3:包含HTML标签 ==========");
ContentRequest request3 = new ContentRequest("这是<b>加粗</b>的内容");
filterChain.filter(request3);
System.out.println("最终结果:" + (request3.isPassed() ? "发布成功" : "发布失败"));
if (request3.isPassed()) {
System.out.println("处理后的内容:" + request3.getContent());
}
System.out.println();
// 测试案例4:包含SQL注入
System.out.println("========== 测试案例4:疑似SQL注入 ==========");
ContentRequest request4 = new ContentRequest("'; DROP TABLE users; --");
filterChain.filter(request4);
System.out.println("最终结果:" + (request4.isPassed() ? "发布成功" : "发布失败"));
}
}
输出结果:
========== 测试案例1:正常内容 ==========
【敏感词过滤器】正在检查内容...
过滤结果:通过
【HTML标签过滤器】正在检查内容...
过滤结果:通过
【SQL注入过滤器】正在检查内容...
过滤结果:通过
最终结果:发布成功
========== 测试案例2:包含敏感词 ==========
【敏感词过滤器】正在检查内容...
过滤结果:不通过 - 内容包含敏感词:暴力
最终结果:发布失败
========== 测试案例3:包含HTML标签 ==========
【敏感词过滤器】正在检查内容...
过滤结果:通过
【HTML标签过滤器】正在检查内容...
过滤结果:已清理HTML标签
【SQL注入过滤器】正在检查内容...
过滤结果:通过
最终结果:发布成功
处理后的内容:这是加粗的内容
========== 测试案例4:疑似SQL注入 ==========
【敏感词过滤器】正在检查内容...
过滤结果:通过
【HTML标签过滤器】正在检查内容...
过滤结果:通过
【SQL注入过滤器】正在检查内容...
过滤结果:不通过 - 内容疑似包含SQL注入攻击
最终结果:发布失败
四、责任链模式的优化
4.1 使用建造者模式优化责任链构建
为了使责任链的构建更加优雅,我们可以结合建造者模式:
/**
* 责任链建造者
*/
public class FilterChainBuilder {
private ContentFilter head;
private ContentFilter tail;
public FilterChainBuilder addFilter(ContentFilter filter) {
if (head == null) {
head = filter;
tail = filter;
} else {
tail.setNextFilter(filter);
tail = filter;
}
return this;
}
public ContentFilter build() {
return head;
}
}
使用示例:
ContentFilter filterChain = new FilterChainBuilder()
.addFilter(new SensitiveWordFilter())
.addFilter(new HtmlTagFilter())
.addFilter(new SqlInjectionFilter())
.build();
4.2 Spring中的责任链模式实现
在Spring框架中,我们可以利用依赖注入来更优雅地实现责任链模式:
/**
* 过滤器接口
*/
public interface Filter {
int getOrder();
void doFilter(ContentRequest request);
}
/**
* 过滤器管理器
*/
@Component
public class FilterChainManager {
@Autowired
private List<Filter> filters;
@PostConstruct
public void init() {
// 按order排序
filters.sort(Comparator.comparingInt(Filter::getOrder));
}
public void executeFilters(ContentRequest request) {
for (Filter filter : filters) {
filter.doFilter(request);
if (!request.isPassed()) {
break;
}
}
}
}
/**
* 具体过滤器实现
*/
@Component
public class SensitiveWordFilterImpl implements Filter {
@Override
public int getOrder() {
return 1;
}
@Override
public void doFilter(ContentRequest request) {
// 过滤逻辑
}
}
五、责任链模式的优缺点
5.1 优点
-
降低耦合度:请求的发送者和接收者解耦,发送者不需要知道是哪个处理者最终处理了请求
-
增强灵活性:可以动态地添加、删除或调整处理者的顺序,而不影响其他代码
-
符合单一职责原则:每个处理者只需关注自己能处理的请求
-
符合开闭原则:增加新的处理者时,不需要修改原有代码
5.2 缺点
-
性能问题:如果责任链过长,会影响性能,因为请求需要遍历整个链
-
调试困难:由于请求是动态分配的,调试时不容易观察运行时的特征
-
可能无法处理:如果没有正确配置责任链,可能导致请求无法被处理
-
建链麻烦:需要在客户端手动建立责任链,增加了客户端的复杂度
六、责任链模式的应用场景
6.1 适用场景
-
多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定
-
需要动态指定处理一组对象的处理顺序
-
不希望明确指定接收者的情况下,向多个对象中的一个提交请求
-
可处理一个请求的对象集合需要被动态指定
6.2 常见应用
- 审批流程:OA系统中的请假、报销等审批
- 日志系统:不同级别的日志处理
- 过滤器:Servlet的Filter链、Spring的拦截器
- 异常处理:多级异常捕获和处理
- 权限验证:多层权限校验
- 事件处理:GUI系统中的事件冒泡机制
七、框架中的责任链模式
7.1 Java Servlet Filter
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 前置处理
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 传递给下一个过滤器
chain.doFilter(request, response);
// 后置处理
System.out.println("EncodingFilter 后置处理");
}
}
7.2 Spring Interceptor
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 前置处理
String token = request.getHeader("token");
if (token == null) {
response.sendError(401, "未登录");
return false; // 中断责任链
}
return true; // 继续传递
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 后置处理
}
}
7.3 Netty Pipeline
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new CustomHandler());
八、责任链模式 vs 其他模式
8.1 责任链模式 vs 装饰者模式
| 对比维度 | 责任链模式 | 装饰者模式 |
|---|---|---|
| 目的 | 将请求传递给链上的某个对象处理 | 动态地给对象添加额外职责 |
| 处理方式 | 只有一个对象处理请求(或都处理) | 所有装饰者都会处理 |
| 顺序 | 按链的顺序传递 | 按装饰的顺序叠加 |
8.2 责任链模式 vs 策略模式
| 对比维度 | 责任链模式 | 策略模式 |
|---|---|---|
| 对象关系 | 链式结构,对象之间有先后顺序 | 平行关系,对象之间相互独立 |
| 选择方式 | 动态决定由哪个对象处理 | 由客户端选择具体策略 |
| 处理数量 | 可能有多个对象处理 | 只有一个策略对象处理 |
九、最佳实践
9.1 设计建议
- 合理控制链的长度:避免责任链过长影响性能
- 提供默认处理:在链的末尾提供默认处理者,避免请求无法处理
- 避免循环引用:注意不要让责任链形成环
- 考虑缓存:对于频繁执行的责任链,可以考虑缓存结果
9.2 代码规范
/**
* 推荐的责任链处理者模板
*/
public abstract class AbstractHandler {
protected AbstractHandler nextHandler;
public AbstractHandler setNext(AbstractHandler handler) {
this.nextHandler = handler;
return handler; // 返回下一个处理者,支持链式调用
}
public final void handle(Request request) {
// 模板方法
if (canHandle(request)) {
doHandle(request);
}
if (nextHandler != null && shouldContinue(request)) {
nextHandler.handle(request);
}
}
protected abstract boolean canHandle(Request request);
protected abstract void doHandle(Request request);
protected boolean shouldContinue(Request request) {
return true; // 默认继续传递
}
}
十、总结
责任链模式是一种非常实用的设计模式,它通过将请求的发送者和接收者解耦,使系统更加灵活和可扩展。在实际开发中,责任链模式被广泛应用于各种场景,如审批流程、过滤器链等。
更多推荐



所有评论(0)