责任链模式
大约 10 分钟
责任链模式
什么是责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许你将请求沿着处理者链进行发送,收到请求后,每个处理者均可对请求进行处理,或将其传给链上的下个处理者。
责任链模式的核心思想是:
- 将发送请求的对象和处理请求的对象解耦
- 让多个对象都有机会处理请求
- 将这些对象连成一条链,并沿着这条链传递请求
为什么需要责任链模式
在实际开发中,我们经常遇到一个请求可能被多个处理者处理的情况,而且处理者的顺序可能很重要。如果直接在客户端代码中指定具体的处理者,会导致代码耦合度高,难以扩展和维护。责任链模式通过将处理者组织成一条链,使得请求可以沿着链传递,直到被处理为止。
责任链模式的结构
责任链模式包含以下几个角色:
- 处理者(Handler):定义一个处理请求的接口
- 具体处理者(ConcreteHandler):实现处理请求的接口,如果可以处理请求则处理,否则将请求转发给下一个处理者
- 客户端(Client):向链上的具体处理者对象提交请求
责任链模式的实现
基本实现
// 抽象处理者
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(String request);
}
// 具体处理者A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
if (request.contains("A")) {
System.out.println("处理者A处理请求: " + request);
} else if (nextHandler != null) {
System.out.println("处理者A无法处理,传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理请求: " + request);
}
}
}
// 具体处理者B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
if (request.contains("B")) {
System.out.println("处理者B处理请求: " + request);
} else if (nextHandler != null) {
System.out.println("处理者B无法处理,传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理请求: " + request);
}
}
}
// 具体处理者C
class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(String request) {
if (request.contains("C")) {
System.out.println("处理者C处理请求: " + request);
} else if (nextHandler != null) {
System.out.println("处理者C无法处理,传递给下一个处理者");
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理请求: " + request);
}
}
}
// 使用示例
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 创建处理者
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
// 构建责任链
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
// 测试请求
System.out.println("=== 测试请求 ===");
handlerA.handleRequest("请求包含A");
System.out.println();
handlerA.handleRequest("请求包含B");
System.out.println();
handlerA.handleRequest("请求包含C");
System.out.println();
handlerA.handleRequest("请求包含D");
}
}
实际应用示例
// 请假审批示例
// 抽象审批者
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 processLeaveRequest(LeaveRequest request);
}
// 请假请求类
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;
}
// Getter方法
public String getEmployee() { return employee; }
public int getDays() { return days; }
public String getReason() { return reason; }
@Override
public String toString() {
return "请假人: " + employee + ", 天数: " + days + ", 原因: " + reason;
}
}
// 班主任审批者
class班主任 extends Approver {
public 班主任(String name) {
super(name);
}
@Override
public void processLeaveRequest(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("班主任 " + name + " 批准了请假请求: " + request);
} else if (nextApprover != null) {
System.out.println("班主任 " + name + " 无法批准 " + request.getDays() + " 天的假期,转交上级处理");
nextApprover.processLeaveRequest(request);
} else {
System.out.println("请假天数过长,无人能够批准: " + request);
}
}
}
// 系主任审批者
class 系主任 extends Approver {
public 系主任(String name) {
super(name);
}
@Override
public void processLeaveRequest(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("系主任 " + name + " 批准了请假请求: " + request);
} else if (nextApprover != null) {
System.out.println("系主任 " + name + " 无法批准 " + request.getDays() + " 天的假期,转交上级处理");
nextApprover.processLeaveRequest(request);
} else {
System.out.println("请假天数过长,无人能够批准: " + request);
}
}
}
// 院长审批者
class 院长 extends Approver {
public 院长(String name) {
super(name);
}
@Override
public void processLeaveRequest(LeaveRequest request) {
if (request.getDays() <= 15) {
System.out.println("院长 " + name + " 批准了请假请求: " + request);
} else if (nextApprover != null) {
System.out.println("院长 " + name + " 无法批准 " + request.getDays() + " 天的假期,转交上级处理");
nextApprover.processLeaveRequest(request);
} else {
System.out.println("请假天数过长,无人能够批准: " + request);
}
}
}
// 校长审批者
class 校长 extends Approver {
public 校长(String name) {
super(name);
}
@Override
public void processLeaveRequest(LeaveRequest request) {
if (request.getDays() <= 30) {
System.out.println("校长 " + name + " 批准了请假请求: " + request);
} else {
System.out.println("请假天数超过30天,需要特殊审批: " + request);
}
}
}
// 使用示例
public class LeaveApprovalDemo {
public static void main(String[] args) {
// 创建审批者
Approver teacher = new 班主任("张老师");
Approver departmentHead = new 系主任("李主任");
Approver dean = new 院长("王院长");
Approver president = new 校长("陈校长");
// 构建审批链
teacher.setNextApprover(departmentHead);
departmentHead.setNextApprover(dean);
dean.setNextApprover(president);
// 测试不同的请假请求
System.out.println("=== 请假审批测试 ===");
LeaveRequest request1 = new LeaveRequest("小明", 2, "生病");
System.out.println("请求1: " + request1);
teacher.processLeaveRequest(request1);
System.out.println();
LeaveRequest request2 = new LeaveRequest("小红", 5, "参加比赛");
System.out.println("请求2: " + request2);
teacher.processLeaveRequest(request2);
System.out.println();
LeaveRequest request3 = new LeaveRequest("小刚", 10, "家庭事务");
System.out.println("请求3: " + request3);
teacher.processLeaveRequest(request3);
System.out.println();
LeaveRequest request4 = new LeaveRequest("小丽", 20, "出国交流");
System.out.println("请求4: " + request4);
teacher.processLeaveRequest(request4);
System.out.println();
LeaveRequest request5 = new LeaveRequest("小强", 40, "长期实习");
System.out.println("请求5: " + request5);
teacher.processLeaveRequest(request5);
}
}
责任链模式的应用场景
- 多级审批流程:如请假审批、费用报销审批等
- 异常处理:在Java异常处理机制中,异常会沿着调用栈向上传播
- 过滤器模式:Web应用中的请求过滤器链
- 日志处理:不同级别的日志由不同的处理器处理
- 事件处理:GUI中的事件冒泡机制
- 拦截器模式:Spring MVC中的拦截器链
责任链模式的优缺点
优点
- 降低耦合度:将发送请求的对象和处理请求的对象解耦
- 增强灵活性:可以动态地增加或删除处理者,改变处理者之间的先后顺序
- 符合开闭原则:增加新的具体处理者无须修改原有代码
- 简化对象:使得对象不需要知道链的结构
缺点
- 不能保证请求一定被处理:可能没有任何处理者处理请求
- 系统性能受影响:请求可能涉及到多个处理对象,系统性能会受到一定影响
- 调试困难:调试时需要跟踪请求在链中的传递过程
责任链模式与其他模式的比较
与命令模式的区别
- 责任链模式:关注请求的传递和处理
- 命令模式:关注将请求封装成对象
与装饰器模式的区别
- 责任链模式:关注请求的传递路径
- 装饰器模式:关注对象功能的增强
与观察者模式的区别
- 责任链模式:请求沿着链传递,直到被处理
- 观察者模式:通知所有观察者
责任链模式的变体
1. 纯责任链模式
// 纯责任链模式:每个处理者要么处理请求,要么转发给下一个处理者
abstract class PureHandler {
protected PureHandler nextHandler;
public void setNextHandler(PureHandler nextHandler) {
this.nextHandler = nextHandler;
}
public final void handleRequest(String request) {
if (canHandle(request)) {
doHandle(request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("没有处理者能够处理请求: " + request);
}
}
protected abstract boolean canHandle(String request);
protected abstract void doHandle(String request);
}
2. 不纯责任链模式
// 不纯责任链模式:处理者可以处理部分请求,然后继续传递
abstract class ImpureHandler {
protected ImpureHandler nextHandler;
public void setNextHandler(ImpureHandler nextHandler) {
this.nextHandler = nextHandler;
}
public void handleRequest(String request) {
// 处理请求的一部分
processRequest(request);
// 继续传递给下一个处理者
if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
protected abstract void processRequest(String request);
}
实际项目中的应用
// Web请求过滤器示例
// 请求过滤器接口
interface RequestFilter {
void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain);
}
// 过滤器链
class FilterChain {
private List<RequestFilter> filters = new ArrayList<>();
private int position = 0;
public void addFilter(RequestFilter filter) {
filters.add(filter);
}
public void doFilter(HttpServletRequest request, HttpServletResponse response) {
if (position < filters.size()) {
RequestFilter filter = filters.get(position++);
filter.doFilter(request, response, this);
} else {
// 所有过滤器都已执行,处理请求
System.out.println("处理请求: " + request.getRequestURI());
}
}
}
// 编码过滤器
class EncodingFilter implements RequestFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
System.out.println("编码过滤器: 设置UTF-8编码");
// 设置请求和响应编码
// request.setCharacterEncoding("UTF-8");
// response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
// 权限过滤器
class AuthFilter implements RequestFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
System.out.println("权限过滤器: 用户已认证");
chain.doFilter(request, response);
} else {
System.out.println("权限过滤器: 用户未认证,拒绝访问");
response.setStatus(401);
}
}
}
// 日志过滤器
class LoggingFilter implements RequestFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
System.out.println("日志过滤器: 记录请求 - " + request.getMethod() + " " + request.getRequestURI());
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long endTime = System.currentTimeMillis();
System.out.println("日志过滤器: 请求处理完成,耗时 " + (endTime - startTime) + "ms");
}
}
// 模拟HttpServletRequest
class HttpServletRequest {
private String requestURI;
private String method;
private Map<String, String> headers = new HashMap<>();
public HttpServletRequest(String requestURI, String method) {
this.requestURI = requestURI;
this.method = method;
}
public String getRequestURI() { return requestURI; }
public String getMethod() { return method; }
public String getHeader(String name) { return headers.get(name); }
public void setHeader(String name, String value) { headers.put(name, value); }
}
// 模拟HttpServletResponse
class HttpServletResponse {
private int status = 200;
public void setStatus(int status) {
this.status = status;
System.out.println("设置响应状态码: " + status);
}
public int getStatus() { return status; }
}
// 使用示例
public class WebFilterDemo {
public static void main(String[] args) {
// 创建过滤器链
FilterChain filterChain = new FilterChain();
// 添加过滤器
filterChain.addFilter(new LoggingFilter());
filterChain.addFilter(new EncodingFilter());
filterChain.addFilter(new AuthFilter());
// 测试已认证的请求
System.out.println("=== 测试已认证请求 ===");
HttpServletRequest request1 = new HttpServletRequest("/api/users", "GET");
request1.setHeader("Authorization", "Bearer token123");
HttpServletResponse response1 = new HttpServletResponse();
filterChain.doFilter(request1, response1);
System.out.println();
// 测试未认证的请求
System.out.println("=== 测试未认证请求 ===");
HttpServletRequest request2 = new HttpServletRequest("/api/orders", "POST");
HttpServletResponse response2 = new HttpServletResponse();
filterChain.doFilter(request2, response2);
}
}
// 日志处理示例
// 日志级别枚举
enum LogLevel {
DEBUG(0), INFO(1), WARN(2), ERROR(3);
private int level;
LogLevel(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
}
// 抽象日志处理器
abstract class Logger {
protected LogLevel level;
protected Logger nextLogger;
public Logger(LogLevel level) {
this.level = level;
}
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
public void logMessage(LogLevel level, String message) {
if (this.level.getLevel() <= level.getLevel()) {
write(message);
}
if (nextLogger != null) {
nextLogger.logMessage(level, message);
}
}
protected abstract void write(String message);
}
// 控制台日志处理器
class ConsoleLogger extends Logger {
public ConsoleLogger(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("控制台日志: " + message);
}
}
// 文件日志处理器
class FileLogger extends Logger {
public FileLogger(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("文件日志: " + message);
}
}
// 错误日志处理器
class ErrorLogger extends Logger {
public ErrorLogger(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("错误日志: " + message);
}
}
// 使用示例
public class LoggerChainDemo {
public static void main(String[] args) {
// 创建日志处理器
Logger errorLogger = new ErrorLogger(LogLevel.ERROR);
Logger fileLogger = new FileLogger(LogLevel.WARN);
Logger consoleLogger = new ConsoleLogger(LogLevel.INFO);
// 构建日志链
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
// 测试不同级别的日志
System.out.println("=== 日志处理测试 ===");
System.out.println("1. DEBUG级别日志:");
errorLogger.logMessage(LogLevel.DEBUG, "这是一个调试信息");
System.out.println("\n2. INFO级别日志:");
errorLogger.logMessage(LogLevel.INFO, "这是一个普通信息");
System.out.println("\n3. WARN级别日志:");
errorLogger.logMessage(LogLevel.WARN, "这是一个警告信息");
System.out.println("\n4. ERROR级别日志:");
errorLogger.logMessage(LogLevel.ERROR, "这是一个错误信息");
}
}
总结
责任链模式是一种非常实用的行为型设计模式,它通过将请求沿着处理者链进行传递,实现了发送请求的对象和处理请求的对象之间的解耦。在实际开发中,当我们需要处理可能被多个处理者处理的请求时,责任链模式是一个很好的选择。
使用责任链模式的关键点:
- 识别出需要链式处理的请求场景
- 定义抽象处理者接口
- 创建具体处理者实现处理逻辑
- 构建处理者链
- 客户端通过链的起始处理者提交请求
责任链模式的优点是可以动态地增加或删除处理者,符合开闭原则,但也需要注意可能无法保证请求一定被处理,以及调试困难等问题。在现代Java开发中,责任链模式广泛应用于Web过滤器、日志处理、异常处理、审批流程等场景。