责任链模式(Chain of Responsibility Pattern)
概述
责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
核心思想
- 将多个对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止
- 发出请求的对象不需要知道链的结构,也不需要知道哪个对象会处理请求
- 降低了对象之间的耦合度
适用场景
- 多个对象可以处理同一请求,但具体由哪个对象处理在运行时动态决定
- 需要动态指定处理请求的对象集合
- 不想让客户端知道具体的处理者
- 需要按顺序执行多个处理器
常见应用场景
- 审批流程:请假审批、报销审批(组长 → 经理 → 总监 → CEO)
- 日志处理:不同级别的日志由不同的处理器处理
- 异常处理:异常沿着调用栈向上传递
- 过滤器链:Servlet Filter、Spring Interceptor
- 权限校验:多级权限验证
- 数据验证:多个验证规则依次执行
UML 类图
┌─────────────────┐
│ Handler │ (抽象处理者)
├─────────────────┤
│ - next: Handler │
├─────────────────┤
│ + setNext() │
│ + handleRequest()│
└─────────────────┘
△
│
├──────────────────┬──────────────────┐
│ │ │
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ConcreteHandler1│ │ConcreteHandler2│ │ConcreteHandler3│
├───────────────┤ ├───────────────┤ ├───────────────┤
│+ handleRequest()│ │+ handleRequest()│ │+ handleRequest()│
└───────────────┘ └───────────────┘ └───────────────┘角色组成
抽象处理者(Handler)
- 定义处理请求的接口
- 维护下一个处理者的引用
具体处理者(ConcreteHandler)
- 实现处理请求的方法
- 判断是否能处理请求,不能则传递给下一个处理者
客户端(Client)
- 创建处理链
- 向链的第一个处理者提交请求
实现方式
方式一:传统实现(链式传递)
每个处理者持有下一个处理者的引用,如果自己不能处理则传递给下一个。
示例:请假审批流程
java
// 抽象处理者
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(LeaveRequest request);
}
// 请假请求
public class LeaveRequest {
private String name;
private int days;
public LeaveRequest(String name, int days) {
this.name = name;
this.days = days;
}
public String getName() { return name; }
public int getDays() { return days; }
}
// 具体处理者:组长(处理 1 天以内的请假)
public class TeamLeader extends Approver {
public TeamLeader(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 1) {
System.out.println("组长 " + name + " 批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else {
System.out.println("组长 " + name + " 无权批准,转交上级");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
// 具体处理者:经理(处理 3 天以内的请假)
public class Manager extends Approver {
public Manager(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("经理 " + name + " 批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else {
System.out.println("经理 " + name + " 无权批准,转交上级");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
// 具体处理者:总监(处理 7 天以内的请假)
public class Director extends Approver {
public Director(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("总监 " + name + " 批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else {
System.out.println("总监 " + name + " 无权批准,转交上级");
if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
}
// 客户端测试
public class Client {
public static void main(String[] args) {
// 创建处理者
Approver teamLeader = new TeamLeader("张三");
Approver manager = new Manager("李四");
Approver director = new Director("王五");
// 构建责任链
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
// 提交请求
LeaveRequest request1 = new LeaveRequest("小明", 1);
teamLeader.processRequest(request1);
// 输出: 组长 张三 批准了 小明 的 1 天请假
System.out.println("---");
LeaveRequest request2 = new LeaveRequest("小红", 3);
teamLeader.processRequest(request2);
// 输出: 组长 张三 无权批准,转交上级
// 经理 李四 批准了 小红 的 3 天请假
System.out.println("---");
LeaveRequest request3 = new LeaveRequest("小刚", 7);
teamLeader.processRequest(request3);
// 输出: 组长 张三 无权批准,转交上级
// 经理 李四 无权批准,转交上级
// 总监 王五 批准了 小刚 的 7 天请假
}
}方式二:集合实现(统一管理)
使用 List 统一管理所有处理者,由链管理器负责调用。
java
// 抽象处理者
public interface Handler {
boolean handle(Request request);
}
// 请求对象
public class Request {
private String type;
private String content;
public Request(String type, String content) {
this.type = type;
this.content = content;
}
public String getType() { return type; }
public String getContent() { return content; }
}
// 具体处理者:日志处理器
public class LogHandler implements Handler {
@Override
public boolean handle(Request request) {
if ("LOG".equals(request.getType())) {
System.out.println("LogHandler 处理日志: " + request.getContent());
return true;
}
return false;
}
}
// 具体处理者:异常处理器
public class ExceptionHandler implements Handler {
@Override
public boolean handle(Request request) {
if ("EXCEPTION".equals(request.getType())) {
System.out.println("ExceptionHandler 处理异常: " + request.getContent());
return true;
}
return false;
}
}
// 责任链管理器
public class HandlerChain {
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
handlers.add(handler);
}
public void process(Request request) {
for (Handler handler : handlers) {
if (handler.handle(request)) {
System.out.println("请求已被处理");
return;
}
}
System.out.println("没有处理者能处理该请求");
}
}
// 客户端测试
public class Client {
public static void main(String[] args) {
HandlerChain chain = new HandlerChain();
chain.addHandler(new LogHandler());
chain.addHandler(new ExceptionHandler());
Request request1 = new Request("LOG", "系统启动");
chain.process(request1);
// 输出: LogHandler 处理日志: 系统启动
// 请求已被处理
Request request2 = new Request("EXCEPTION", "空指针异常");
chain.process(request2);
// 输出: ExceptionHandler 处理异常: 空指针异常
// 请求已被处理
}
}方式三:Spring 实现(依赖注入)
利用 Spring 的依赖注入和 @Order 注解管理责任链。
java
// 抽象处理者
public interface ValidationHandler {
boolean validate(User user);
int getOrder();
}
// 用户对象
@Data
public class User {
private String username;
private String password;
private Integer age;
}
// 具体处理者:用户名验证
@Component
@Order(1)
public class UsernameValidationHandler implements ValidationHandler {
@Override
public boolean validate(User user) {
if (user.getUsername() == null || user.getUsername().isEmpty()) {
System.out.println("用户名不能为空");
return false;
}
System.out.println("用户名验证通过");
return true;
}
@Override
public int getOrder() {
return 1;
}
}
// 具体处理者:密码验证
@Component
@Order(2)
public class PasswordValidationHandler implements ValidationHandler {
@Override
public boolean validate(User user) {
if (user.getPassword() == null || user.getPassword().length() < 6) {
System.out.println("密码长度不能少于6位");
return false;
}
System.out.println("密码验证通过");
return true;
}
@Override
public int getOrder() {
return 2;
}
}
// 具体处理者:年龄验证
@Component
@Order(3)
public class AgeValidationHandler implements ValidationHandler {
@Override
public boolean validate(User user) {
if (user.getAge() == null || user.getAge() < 18) {
System.out.println("年龄必须大于18岁");
return false;
}
System.out.println("年龄验证通过");
return true;
}
@Override
public int getOrder() {
return 3;
}
}
// 验证服务
@Service
@RequiredArgsConstructor
public class UserValidationService {
private final List<ValidationHandler> handlers;
public boolean validateUser(User user) {
// Spring 会自动按 @Order 排序注入
for (ValidationHandler handler : handlers) {
if (!handler.validate(user)) {
return false;
}
}
return true;
}
}
// 控制器
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserValidationService validationService;
@PostMapping("/register")
public String register(@RequestBody User user) {
if (validationService.validateUser(user)) {
return "注册成功";
}
return "注册失败";
}
}实际应用场景
1. Servlet Filter 过滤器链
java
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 认证逻辑
System.out.println("执行认证过滤器");
// 传递给下一个过滤器
chain.doFilter(request, response);
}
}
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 日志记录
System.out.println("执行日志过滤器");
// 传递给下一个过滤器
chain.doFilter(request, response);
}
}2. Spring Interceptor 拦截器链
java
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 登录检查
String token = request.getHeader("token");
if (token == null) {
response.setStatus(401);
return false; // 中断链
}
return true; // 继续执行
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register");
}
}3. MyBatis 插件拦截器链
java
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class SqlLogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("执行 SQL 日志拦截器");
return invocation.proceed(); // 继续执行
}
}优点
降低耦合度
- 请求发送者和接收者解耦
- 发送者不需要知道具体哪个对象会处理请求
增强灵活性
- 可以动态添加或删除处理者
- 可以改变处理者的顺序
符合单一职责原则
- 每个处理者只负责自己的处理逻辑
符合开闭原则
- 新增处理者不需要修改现有代码
缺点
性能问题
- 请求可能需要遍历整个链才能被处理
- 链过长会影响性能
调试困难
- 请求的处理路径不明确
- 难以追踪请求在哪个环节被处理
不保证请求被处理
- 如果链配置不当,请求可能到达链尾仍未被处理
- 需要有兜底处理机制
可能产生循环调用
- 如果链配置错误,可能导致死循环
使用注意事项
避免链过长
- 控制处理者数量,避免性能问题
- 考虑使用其他设计模式(如策略模式)
确保请求被处理
- 在链尾添加默认处理者
- 或者抛出异常提示未处理
明确处理者职责
- 每个处理者只处理特定类型的请求
- 避免职责重叠
考虑线程安全
- 如果处理者有状态,需要考虑并发问题
- 建议使用无状态的处理者
与其他模式的对比
责任链模式 vs 策略模式
| 对比项 | 责任链模式 | 策略模式 |
|---|---|---|
| 处理方式 | 多个处理者依次处理 | 选择一个策略处理 |
| 处理者数量 | 可以有多个处理者参与 | 只有一个策略执行 |
| 选择时机 | 运行时动态选择 | 通常在创建时选择 |
| 适用场景 | 多级审批、过滤器链 | 算法替换、支付方式 |
责任链模式 vs 装饰器模式
| 对比项 | 责任链模式 | 装饰器模式 |
|---|---|---|
| 目的 | 处理请求 | 增强功能 |
| 中断性 | 可以中断链 | 不能中断 |
| 顺序 | 顺序重要 | 顺序可能不重要 |
| 返回值 | 可能不返回 | 通常有返回值 |
总结
责任链模式是一种非常实用的行为设计模式,特别适合以下场景:
- 多级审批流程:请假审批、报销审批、采购审批
- 过滤器链:Web 过滤器、拦截器、插件系统
- 数据验证:多个验证规则依次执行
- 日志处理:不同级别的日志由不同处理器处理
- 异常处理:异常沿着调用栈向上传递
关键要点
- 解耦请求发送者和接收者:发送者不需要知道谁会处理请求
- 动态组合处理者:可以灵活地添加、删除、重排处理者
- 单一职责:每个处理者只负责自己的处理逻辑
- 注意性能:避免链过长,确保请求能被处理
实现建议
- 传统链式实现:适合处理者固定、顺序明确的场景
- 集合管理实现:适合处理者动态变化的场景
- Spring 依赖注入:适合企业级应用,利用框架特性
责任链模式在 Java Web 开发中应用广泛,掌握这个模式对理解 Servlet Filter、Spring Interceptor 等框架机制非常有帮助。