设计模式之十五:责任链模式从理论到实战一篇搞定
在软件开发中,我们经常遇到需要多个对象处理同一请求的场景。比如请假审批流程需要不同级别的领导审批、日志系统需要根据日志级别决定输出方式、Web请求需要经过一系列过滤器的处理…请求需要经过一系列处理步骤,每个步骤可能处理请求,也可能将其传递给下一个步骤。责任链模式(Chain of Responsibility Pattern)正是为这类问题提供了优雅的解决方案。本文将深入浅出地介绍责任链模式,并通
前言
在软件开发中,我们经常遇到需要多个对象处理同一请求的场景。比如请假审批流程需要不同级别的领导审批、日志系统需要根据日志级别决定输出方式、Web请求需要经过一系列过滤器的处理…这些场景都有一个共同特点:请求需要经过一系列处理步骤,每个步骤可能处理请求,也可能将其传递给下一个步骤。
责任链模式(Chain of Responsibility Pattern)正是为这类问题提供了优雅的解决方案。本文将深入浅出地介绍责任链模式,并通过Java示例和Spring Boot实战,帮助你掌握这一强大工具。
1. 责任链模式概述
1.1 什么是责任链模式?
责任链模式是一种行为型设计模式,它创建了一个对象链,每个对象都有机会处理请求。请求沿着这条链传递,直到有一个对象处理它为止,或者直到链的末端。
这种模式的核心思想是:解耦请求的发送者和接收者,让多个接收者都有机会处理请求,而发送者不需要知道具体哪个接收者处理了请求。
1.2 生活中的类比
想象一下你为电脑新买了一个硬件设备,但Linux系统不支持它。你拨打技术支持电话:
- 首先听到自动回复器,提供常见解决方案,但你的问题不在其中
- 自动回复器将你转接到人工接听人员,他翻阅手册但仍无法解决
- 接听人员将你转给真正的工程师,他终于告诉了你正确的驱动程序下载地址
这就是一个典型的责任链——你的问题(请求)沿着支持人员(处理者)组成的链传递,直到找到能解决它的人。
2. 责任链模式的结构
2.1 核心角色
责任链模式主要包含以下几个角色:
| 角色 | 职责 |
|---|---|
| 抽象处理者(Handler) | 定义处理请求的接口,包含指向下一个处理者的引用 |
| 具体处理者(ConcreteHandler) | 实现处理逻辑,如果能处理则处理,否则传递给下一个 |
| 客户端(Client) | 创建处理者对象并构建责任链,向链发送请求 |
2.2 类图结构
┌─────────────┐ ┌─────────────────┐
│ Client │──────▶│ Handler │
└─────────────┘ │─────────────────│
│+next: Handler │
│+setNext() │
│+handleRequest() │
└────────┬────────┘
▲
┌────────────┴────────────┐
│ │
┌─────────┴─────────┐ ┌─────────┴─────────┐
│ ConcreteHandler1 │ │ ConcreteHandler2 │
│───────────────────│ │───────────────────│
│+handleRequest() │ │+handleRequest() │
└───────────────────┘ └───────────────────┘
3. Java示例:请假审批系统
让我们通过一个实际的请假审批案例来理解责任链模式的实现。规则如下:
- 请假 1-3 天:部门主管审批
- 请假 4-7 天:部门经理审批
- 请假 8-30 天:总经理审批
- 请假超过 30 天:不予批准
3.1 创建请求类
// 请假请求类
public class LeaveRequest {
private String employeeName; // 员工姓名
private int leaveDays; // 请假天数
public LeaveRequest(String employeeName, int leaveDays) {
this.employeeName = employeeName;
this.leaveDays = leaveDays;
}
// getter方法
public String getEmployeeName() {
return employeeName;
}
public int getLeaveDays() {
return leaveDays;
}
}
3.2 创建抽象处理者
// 抽象审批者
public abstract class Approver {
// 下一个审批者
protected Approver nextApprover;
// 设置下一个审批者
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
// 处理请假请求的抽象方法
public abstract void processRequest(LeaveRequest request);
}
3.3 创建具体处理者
// 部门主管
public class Director extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理1-3天的请假
if (request.getLeaveDays() >= 1 && request.getLeaveDays() <= 3) {
System.out.println("部门主管批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天");
}
// 超过3天则交给下一个审批者
else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 部门经理
public class Manager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理4-7天的请假
if (request.getLeaveDays() >= 4 && request.getLeaveDays() <= 7) {
System.out.println("部门经理批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天");
}
// 超过7天则交给下一个审批者
else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 总经理
public class GeneralManager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理8-30天的请假
if (request.getLeaveDays() >= 8 && request.getLeaveDays() <= 30) {
System.out.println("总经理批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天");
}
// 超过30天则不予批准
else {
System.out.println(request.getEmployeeName() + " 请假 " +
request.getLeaveDays() + " 天,超过最大允许天数,不予批准");
}
}
}
3.4 客户端使用
public class Client {
public static void main(String[] args) {
// 创建各个审批者
Approver director = new Director();
Approver manager = new Manager();
Approver generalManager = new GeneralManager();
// 构建责任链:部门主管 -> 部门经理 -> 总经理
director.setNextApprover(manager);
manager.setNextApprover(generalManager);
// 创建不同的请假请求
LeaveRequest request1 = new LeaveRequest("张三", 2);
LeaveRequest request2 = new LeaveRequest("李四", 5);
LeaveRequest request3 = new LeaveRequest("王五", 15);
LeaveRequest request4 = new LeaveRequest("赵六", 35);
// 处理请求
director.processRequest(request1);
director.processRequest(request2);
director.processRequest(request3);
director.processRequest(request4);
}
}
运行结果:
部门主管批准 张三 请假 2 天
部门经理批准 李四 请假 5 天
总经理批准 王五 请假 15 天
赵六 请假 35 天,超过最大允许天数,不予批准
4. Spring Boot中的责任链模式应用
在Spring Boot项目中,责任链模式可以帮助我们实现复杂接口的解耦和动态编排。下面以订单处理系统为例,展示如何在Spring Boot中优雅地实现责任链模式。
4.1 场景描述
假设我们有一个订单处理系统,订单需要经过多个环节的处理:
- 验证订单:检查订单是否有效
- 计算金额:计算订单总金额(含税等)
- 检查库存:确认商品库存充足
- 处理支付:执行支付操作
4.2 定义处理器接口
public interface OrderHandler {
/**
* 处理订单
* @param order 订单对象
*/
void handle(Order order);
/**
* 设置下一个处理器
* @param nextHandler 下一个处理器
*/
void setNextHandler(OrderHandler nextHandler);
}
4.3 创建订单类
public class Order {
private Long id;
private double amount; // 订单金额
private boolean valid; // 是否有效
private String productId; // 商品ID
private int stock; // 库存数量
private boolean paymentSuccess; // 支付是否成功
// 构造方法、getter和setter
public Order(Long id, double amount, boolean valid, String productId, int stock) {
this.id = id;
this.amount = amount;
this.valid = valid;
this.productId = productId;
this.stock = stock;
}
// getter和setter方法
public Long getId() { return id; }
public double getAmount() { return amount; }
public void setAmount(double amount) { this.amount = amount; }
public boolean isValid() { return valid; }
public void setValid(boolean valid) { this.valid = valid; }
public String getProductId() { return productId; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
public boolean isPaymentSuccess() { return paymentSuccess; }
public void setPaymentSuccess(boolean paymentSuccess) { this.paymentSuccess = paymentSuccess; }
}
4.4 实现具体处理器(使用Spring注解)
@Component
public class OrderValidationHandler implements OrderHandler {
private OrderHandler nextHandler;
@Override
public void handle(Order order) {
System.out.println("【1.验证订单】验证订单有效性...");
// 执行订单验证逻辑
if (order.isValid()) {
System.out.println(" 订单验证通过");
if (nextHandler != null) {
nextHandler.handle(order);
}
} else {
System.out.println(" 订单验证失败,终止处理");
}
}
@Override
public void setNextHandler(OrderHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
@Component
public class OrderCalculationHandler implements OrderHandler {
private OrderHandler nextHandler;
@Override
public void handle(Order order) {
System.out.println("【2.计算金额】计算订单金额...");
// 执行订单金额计算逻辑(加上10%的税)
double originalAmount = order.getAmount();
double finalAmount = originalAmount * 1.1;
order.setAmount(finalAmount);
System.out.println(" 原金额:" + originalAmount + ",税后金额:" + finalAmount);
if (nextHandler != null) {
nextHandler.handle(order);
}
}
@Override
public void setNextHandler(OrderHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
@Component
public class OrderStockHandler implements OrderHandler {
private OrderHandler nextHandler;
@Override
public void handle(Order order) {
System.out.println("【3.检查库存】检查商品库存...");
// 模拟库存检查(假设需要5件库存)
int requiredStock = 5;
if (order.getStock() >= requiredStock) {
System.out.println(" 库存充足,扣除库存");
order.setStock(order.getStock() - requiredStock);
if (nextHandler != null) {
nextHandler.handle(order);
}
} else {
System.out.println(" 库存不足,终止处理");
}
}
@Override
public void setNextHandler(OrderHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
@Component
public class OrderPaymentHandler implements OrderHandler {
private OrderHandler nextHandler;
@Override
public void handle(Order order) {
System.out.println("【4.处理支付】执行支付操作...");
// 执行支付逻辑
if (order.getAmount() > 0) {
System.out.println(" 支付成功!订单金额:" + order.getAmount());
order.setPaymentSuccess(true);
// 这是最后一个处理器,不再传递
} else {
System.out.println(" 支付失败:金额无效");
order.setPaymentSuccess(false);
}
}
@Override
public void setNextHandler(OrderHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
4.5 配置责任链(Spring配置类)
@Configuration
public class OrderChainConfig {
@Autowired
private OrderValidationHandler validationHandler;
@Autowired
private OrderCalculationHandler calculationHandler;
@Autowired
private OrderStockHandler stockHandler;
@Autowired
private OrderPaymentHandler paymentHandler;
/**
* 组装责任链:验证 -> 计算 -> 库存 -> 支付
*/
@Bean
public OrderHandler orderHandlerChain() {
validationHandler.setNextHandler(calculationHandler);
calculationHandler.setNextHandler(stockHandler);
stockHandler.setNextHandler(paymentHandler);
// 支付处理器是最后一个,不需要设置下一个
return validationHandler; // 返回链的第一个处理器
}
}
4.6 创建订单服务
@Service
public class OrderService {
@Autowired
private OrderHandler orderHandlerChain;
/**
* 处理订单
*/
public void processOrder(Order order) {
System.out.println("========== 开始处理订单 ==========");
orderHandlerChain.handle(order);
System.out.println("========== 订单处理完成 ==========");
System.out.println("最终订单状态:" +
(order.isPaymentSuccess() ? "支付成功" : "处理失败"));
}
}
4.7 控制器层调用
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/process/{id}")
public String processOrder(@PathVariable Long id) {
// 模拟创建订单
Order order = new Order(id, 100.0, true, "PROD-001", 10);
// 处理订单
orderService.processOrder(order);
return "订单处理完成,支付状态:" + order.isPaymentSuccess();
}
}
4.8 运行结果
启动Spring Boot应用,访问 /api/orders/process/123,控制台输出:
========== 开始处理订单 ==========
【1.验证订单】验证订单有效性...
订单验证通过
【2.计算金额】计算订单金额...
原金额:100.0,税后金额:110.0
【3.检查库存】检查商品库存...
库存充足,扣除库存
【4.处理支付】执行支付操作...
支付成功!订单金额:110.0
========== 订单处理完成 ==========
最终订单状态:支付成功
5. 责任链模式的变种
除了标准的线性责任链,还有其他几种常见形式:
5.1 Pipeline-Valve模型(Tomcat风格)
这种模型的特点是有一个基础的Valve(BaseValve)始终在链的最后执行,且不可删除:
public interface Valve {
Valve getNextValve();
void setNextValve(Valve next);
void invoke(ValveContext context);
}
public interface Pipeline {
void setBasic(Valve valve); // 设置基础Valve
void addValve(Valve valve); // 添加普通Valve
void process(ValveContext context); // 启动处理
}
5.2 其他变种
- 环形责任链:最后一个处理者指向第一个处理者
- 树形责任链:一个处理者可以有多个后继者
- 带条件的责任链:根据条件动态决定下一个处理者
6. 责任链模式的优缺点
6.1 优点
| 优点 | 说明 |
|---|---|
| 降低耦合度 | 请求的发送者和接收者解耦,发送者无需知道谁处理了请求 |
| 灵活性高 | 可以灵活地改变链的结构和处理顺序 |
| 符合开闭原则 | 新增处理者不需要修改原有代码 |
| 单一职责原则 | 每个处理者只需关注自己的职责范围 |
| 控制处理顺序 | 可以精确控制请求处理的顺序 |
6.2 缺点
| 缺点 | 说明 |
|---|---|
| 请求可能不被处理 | 如果链中没有对象能处理请求,请求可能会被丢弃 |
| 调试复杂 | 请求的处理路径可能较长,调试时需要跟踪整个链 |
| 性能影响 | 对于长链,循环调用可能带来一定的性能开销 |
| 可能形成循环 | 如果不慎形成环形链,可能导致死循环 |
7. 使用场景总结
责任链模式适用于以下场景:
7.1 常见应用场景
| 场景类别 | 具体示例 |
|---|---|
| 审批流程 | 请假审批、报销审批、采购审批等多级审批 |
| 日志系统 | 不同级别(DEBUG/INFO/ERROR)的日志由不同处理器处理 |
| Web过滤器 | Servlet Filter、Spring Interceptor 组成的过滤器链 |
| 权限验证 | 登录认证、权限检查、角色验证等依次执行 |
| 异常处理 | 多层异常捕获处理机制 |
| 事件冒泡 | GUI中的事件传递机制(如JavaScript事件冒泡) |
| 订单处理 | 电商订单的验证、计算、库存、支付等环节 |
7.2 Java标准库中的责任链模式
责任链模式在Java核心库和主流框架中有着广泛应用:
- Servlet Filter:所有Filter组成一个链,依次处理请求
- Spring Interceptor:拦截器链对请求进行预处理和后处理
- Spring Security:过滤器链处理认证和授权
- Netty ChannelPipeline:处理网络事件的责任链
- Java异常处理:try-catch块的嵌套本质上也是一种责任链
- Java日志框架:java.util.logging.Logger会将日志记录请求传递给父处理器
8. 最佳实践建议
在使用责任链模式时,以下几点值得注意:
- 避免过长的责任链:过长的链会影响性能,考虑使用异步或限制链长度
- 确保请求能被处理:可以在链的末尾添加一个兜底处理器,处理未被处理的请求
- 合理划分职责:每个处理者应该职责单一,避免处理逻辑过于复杂
- 考虑线程安全:如果责任链被多个线程共享,需要考虑处理器的线程安全性
- 支持动态编排:结合Spring容器,可以在运行时动态调整处理链的顺序
- 记录处理链路:添加日志或追踪ID,便于调试和监控
总结
责任链模式通过构建处理者对象链,让请求在链中传递直至被处理,有效解耦了请求发送者和接收者。它特别适合处理那些需要多级处理或动态调整处理流程的场景。
在Spring Boot项目中,结合依赖注入和配置类,我们可以非常优雅地实现责任链模式,实现业务逻辑的解耦和动态编排。无论是请假审批、订单处理还是权限验证,责任链模式都能让你的代码更加灵活、可扩展,更好地应对复杂业务场景的变化。
更多推荐


所有评论(0)