一、什么是责任链模式?
责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,使多个对象都有机会处理请求,避免请求发送者与具体处理者之间的紧耦合。
核心角色
抽象处理者(Handler)
- 定义处理请求的接口,包含一个指向下一个处理者的引用(
nextHandler
)。 - 提供设置后续处理者的方法(
setNextHandler
),用于构建责任链。
- 定义处理请求的接口,包含一个指向下一个处理者的引用(
具体处理者(ConcreteHandler)
- 实现抽象处理者的处理方法,判断自己是否有权限处理请求:
- 若有权,处理请求并结束流程;
- 若无权,将请求传递给后续处理者(
nextHandler.handleRequest
)。
- 实现抽象处理者的处理方法,判断自己是否有权限处理请求:
客户端(Client)
- 创建责任链,并向链的起点发送请求,无需知道具体是哪个处理者处理了请求。
二、责任链模式的核心思想
责任链模式的核心是 “链式传递” 和 “责任分配” 的分离。
- 链式传递:请求从链的起点开始,依次传递给每个处理者,直到某个处理者处理它。
- 责任分配:每个处理者只负责自己职责范围内的请求,超出范围的请求则传递给下一个处理者。
生活中的例子
想象你在公司提交一个报销申请,流程如下:
- 直接主管审批(1000元以下);
- 部门经理审批(1000-5000元);
- 财务总监审批(5000元以上)。
这就是一个典型的责任链模式,每个审批人只处理自己权限范围内的请求,超出权限则传递给下一个审批人。
三、Java实现责任链模式
1. 基础示例:请假审批系统
(1)定义抽象处理者
// 抽象处理者类:定义了处理请求的接口和设置下一个处理者的方法
public abstract class LeaveHandler {
// 持有下一个处理者的引用,形成链式结构
protected LeaveHandler nextHandler;
// 设置下一个处理者
public void setNextHandler(LeaveHandler nextHandler) {
this.nextHandler = nextHandler;
}
// 抽象方法:具体处理者需要实现该方法来处理请求
public abstract void handleRequest(LeaveRequest request);
}
(2)定义具体处理者
// 具体处理者:小组长,处理1-3天的请假请求
public class TeamLeader extends LeaveHandler {
@Override
public void handleRequest(LeaveRequest request) {
// 判断是否在自己的处理范围内
if (request.getDays() <= 3) {
System.out.println("小组长批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else if (nextHandler != null) {
// 超出处理范围且存在下一个处理者,将请求传递
nextHandler.handleRequest(request);
} else {
// 没有合适的处理者
System.out.println("无人能处理该请求");
}
}
}
// 具体处理者:经理,处理3-7天的请假请求
public class Manager extends LeaveHandler {
@Override
public void handleRequest(LeaveRequest request) {
// 判断是否在自己的处理范围内
if (request.getDays() <= 7) {
System.out.println("经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else if (nextHandler != null) {
// 超出处理范围且存在下一个处理者,将请求传递
nextHandler.handleRequest(request);
} else {
// 没有合适的处理者
System.out.println("无人能处理该请求");
}
}
}
// 具体处理者:总监,处理7天以上的请假请求
public class Director extends LeaveHandler {
@Override
public void handleRequest(LeaveRequest request) {
// 判断是否在自己的处理范围内
if (request.getDays() > 7) {
System.out.println("总监批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else if (nextHandler != null) {
// 超出处理范围且存在下一个处理者,将请求传递
nextHandler.handleRequest(request);
} else {
// 没有合适的处理者
System.out.println("无人能处理该请求");
}
}
}
(3)定义请求类
// 请假请求类:封装了请假的相关信息
public class LeaveRequest {
private String name; // 请假人姓名
private int days; // 请假天数
private String reason; // 请假原因
public LeaveRequest(String name, int days, String reason) {
this.name = name;
this.days = days;
this.reason = reason;
}
// 以下是获取请假信息的方法
public String getName() { return name; }
public int getDays() { return days; }
public String getReason() { return reason; }
}
(4)客户端调用
// 客户端类:构建责任链并提交请求
public class Client {
public static void main(String[] args) {
// 1. 构建责任链:按照 小组长 -> 经理 -> 总监 的顺序设置
LeaveHandler teamLeader = new TeamLeader();
LeaveHandler manager = new Manager();
LeaveHandler director = new Director();
// 设置责任链顺序
teamLeader.setNextHandler(manager);
manager.setNextHandler(director);
// 2. 创建请假请求
LeaveRequest request1 = new LeaveRequest("张三", 2, "生病"); // 2天请假,应由小组长处理
LeaveRequest request2 = new LeaveRequest("李四", 10, "家庭事务"); // 10天请假,应由总监处理
// 3. 提交请求到责任链的起点(小组长)
// 当调用 teamLeader.handleRequest(request1) 时:
// - 小组长判断2天 <=3天,直接处理该请求
teamLeader.handleRequest(request1);
// 当调用 teamLeader.handleRequest(request2) 时:
// - 小组长判断10天 >3天,将请求传递给经理
// - 经理判断10天 >7天,将请求传递给总监
// - 总监判断10天 >7天,处理该请求
teamLeader.handleRequest(request2);
}
}
⑸、流程图和内存图
2.责任链模式的经典实现
下面通过一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限:
(1)定义抽象处理者
// Approver.java
public abstract class Approver {
protected Approver successor; // 下一个处理者
// 设置下一个处理者
public void setSuccessor(Approver successor) {
this.successor = successor;
}
// 处理请求的抽象方法
public abstract void processRequest(PurchaseRequest request);
}
(2)定义具体处理者
// Director.java
public class Director extends Approver {
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 10000) {
System.out.println("主任审批了金额为 " + request.getAmount() + " 的采购申请");
} else if (successor != null) {
successor.processRequest(request);
}
}
}
// Manager.java
public class Manager extends Approver {
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 50000) {
System.out.println("经理审批了金额为 " + request.getAmount() + " 的采购申请");
} else if (successor != null) {
successor.processRequest(request);
}
}
}
// VicePresident.java
public class VicePresident extends Approver {
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 100000) {
System.out.println("副总裁审批了金额为 " + request.getAmount() + " 的采购申请");
} else if (successor != null) {
successor.processRequest(request);
}
}
}
// President.java
public class President extends Approver {
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 500000) {
System.out.println("总裁审批了金额为 " + request.getAmount() + " 的采购申请");
} else {
System.out.println("金额过大,需要董事会讨论");
}
}
}
(3)定义请求类
// PurchaseRequest.java
public class PurchaseRequest {
private double amount; // 金额
private String purpose; // 用途
public PurchaseRequest(double amount, String purpose) {
this.amount = amount;
this.purpose = purpose;
}
public double getAmount() {
return amount;
}
public String getPurpose() {
return purpose;
}
}
(4)客户端调用
// Client.java
public class Client {
public static void main(String[] args) {
// 创建处理者
Approver director = new Director();
Approver manager = new Manager();
Approver vicePresident = new VicePresident();
Approver president = new President();
// 设置责任链
director.setSuccessor(manager);
manager.setSuccessor(vicePresident);
vicePresident.setSuccessor(president);
// 创建采购申请
PurchaseRequest request1 = new PurchaseRequest(5000, "购买办公用品");
PurchaseRequest request2 = new PurchaseRequest(30000, "购买电脑设备");
PurchaseRequest request3 = new PurchaseRequest(80000, "购买服务器");
PurchaseRequest request4 = new PurchaseRequest(300000, "购买办公大楼");
// 处理请求
director.processRequest(request1);
director.processRequest(request2);
director.processRequest(request3);
director.processRequest(request4);
}
}
在这个示例中,我们创建了一个审批链,从主任到经理、副总裁,最后到总裁。每个审批者根据自己的权限处理请求,如果无法处理则将请求传递给下一个审批者。客户端只需要将请求发送给链头的处理者,无需关心具体是哪个处理者最终处理了请求。
四、责任链模式在 Java 中的实际应用
责任链模式在 Java 中有许多实际应用场景,例如:
- Servlet 过滤器链:在 Java Web 应用中,Servlet 过滤器可以形成一个链,每个过滤器负责特定的任务,如编码转换、权限验证等。
- 日志记录系统:不同级别的日志可以由不同的处理器处理,如控制台日志、文件日志、数据库日志等。
- 异常处理链:多个异常处理器可以按顺序尝试处理异常。
下面是一个使用 Java 8 函数式编程简化责任链模式的示例:
import java.util.function.Consumer;
public class FunctionalChainExample {
public static void main(String[] args) {
// 定义处理者
Consumer<String> logger = message -> System.out.println("日志记录: " + message);
Consumer<String> authChecker = message -> {
if (message.contains("admin")) {
System.out.println("权限验证通过");
} else {
System.out.println("权限验证失败");
}
};
Consumer<String> processor = message -> System.out.println("处理请求: " + message);
// 构建责任链
Consumer<String> chain = logger
.andThen(authChecker)
.andThen(processor);
// 处理请求
chain.accept("admin:create_user");
chain.accept("user:view_profile");
}
}
这个示例使用 Java 8 的函数式接口和方法引用简化了责任链的实现,使代码更加简洁和灵活。
责任链模式的优缺点
优点:
- 降低了请求发送者和接收者之间的耦合度。
- 可以动态添加或修改处理者,提高了系统的灵活性。
- 简化了对象间的连接,每个对象只需保持一个后续者引用。
缺点:
- 请求可能无法被处理,因为链中没有合适的处理者。
- 如果责任链过长,可能会影响系统性能。
- 调试时可能会比较困难,因为请求的处理过程是隐式的。
总结
责任链模式是一种非常实用的设计模式,它将请求的发送者和接收者解耦,使多个处理者都有机会处理请求。通过合理地使用责任链模式,可以提高系统的灵活性和可维护性。在实际开发中,我们可以根据具体需求选择传统的实现方式或使用函数式编程进行简化。无论是 Servlet 过滤器链还是日志处理系统,责任链模式都能发挥其独特的优势。