责任链如涓涓细流,承接请求的起伏,层层传递,直至最终的决断。
一、审批流程
场景假设:有一个简单的需求,根据用户输入的金额,判断是否可以进行购买。如果金额大于等于 1000 元,则需要经过经理、总监和 CEO 的审批,否则直接通过。
public class PurchaseApproval {
public static void main(String[] args) {
BigDecimal amount = new BigDecimal("1500.00"); // 假设用户输入的金额
// 判断是否需要审批
if (amount.compareTo(BigDecimal.valueOf(1000)) >= 0) {
// 经理审批
boolean managerApproval = approveByManager(amount);
if (managerApproval) {
// 总监审批
boolean directorApproval = approveByDirector(amount);
if (directorApproval) {
// CEO审批
boolean ceoApproval = approveByCEO(amount);
if (ceoApproval) {
System.out.println("购买已批准");
} else {
System.out.println("CEO拒绝购买");
}
} else {
System.out.println("总监拒绝购买");
}
} else {
System.out.println("经理拒绝购买");
}
} else {
System.out.println("直接通过购买");
}
}
private static boolean approveByManager(BigDecimal amount) {
// 实际的经理审批逻辑
return true; // 假设经理总是批准
}
private static boolean approveByDirector(BigDecimal amount) {
// 实际的总监审批逻辑
return true; // 假设总监总是批准
}
private static boolean approveByCEO(BigDecimal amount) {
// 实际的CEO审批逻辑
return true; // 假设CEO总是批准
}
}
上面的代码虽然能够实现需求,但存在以下问题:
- 耦合性增加:各个审批步骤之间紧密耦合,修改其中一个步骤可能影响其他步骤。
- 代码冗余:每个审批步骤都需要在同一个方法中判断和处理,导致代码冗长且难以维护。
- 难以扩展:如果需要添加新的审批步骤,就需要修改现有的代码,违反了开闭原则。
二、责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型
设计模式,它允许多个对象(处理器或处理者)依次处理请求,直到其中一个对象处理该请求为止。责任链模式主要用于解耦发送者和接收者之间的复杂请求处理逻辑。
三、责任链模式的核心组成
责任链模式的核心组成部分包括以下几个要素:
- 请求对象(Request):表示需要处理的请求。通常是一个包含请求信息的类,例如金额、用户信息等。
- 处理器接口(Handler):定义了处理请求的方法。处理器可以是抽象类或接口,其中的方法约定了返回值的含义:
- 返回 Boolean.TRUE 表示处理成功。
- 返回 Boolean.FALSE 表示拒绝。
- 返回 null 表示交给下一个处理器。
- 具体处理器(Concrete Handler):实现了处理器接口,负责具体的处理逻辑。每个具体处理器都可以处理请求,或者将请求传递给下一个处理器。
- 客户端(Client):创建责任链并触发请求的地方。客户端将请求发送给责任链的第一个处理器,然后责任链会依次处理请求,直到有一个处理器成功处理为止。
在上面的类图中:
- Handler 是处理请求的接口,定义了处理请求和设置下一个处理者的方法。
- ConcreteHandler1 和 ConcreteHandler2 是具体的处理者,实现了 Handler 接口,并包含一个指向下一个处理者的引用。
- Request 封装了请求的内容。
四、运用责任链模式
场景假设:有一个简单的需求,根据用户输入的金额,判断是否可以进行购买。如果金额大于等于 1000 元,则需要经过经理、总监和 CEO 的审批,否则直接通过。
-
定义处理请求的接口: 首先,定义一个处理请求的接口 ApprovalHandler,包括处理请求和设置下一个处理者的方法。
/** * Request 类用于封装购买请求的信息,包括请求的名称和金额。 */ public class Request { private String name; // 请求的名称,例如 "Purchase Request" private BigDecimal amount; // 请求的金额,表示购买金额 /** * 构造函数,用于创建一个 Request 对象。 * * @param name 请求的名称,例如 "Purchase Request" * @param amount 请求的金额,表示需要购买的数值大小,以 BigDecimal 类型表示精确的数值 */ public Request(String name, BigDecimal amount) { this.name = name; this.amount = amount; } /** * 获取请求的名称。 * * @return 请求的名称 */ public String getName() { return name; } /** * 获取请求的金额。 * * @return 请求的金额,以 BigDecimal 类型返回 */ public BigDecimal getAmount() { return amount; } } /** * ApprovalHandler 接口定义了处理请求和设置下一个处理者的方法。 */ public interface ApprovalHandler { /** * 处理请求的方法。 * * @param request 购买请求对象,包含购买的名称和金额 */ void handleRequest(Request request); /** * 设置下一个处理者的方法。 * * @param nextHandler 下一个处理者对象 */ void setNextHandler(ApprovalHandler nextHandler); }
-
实现具体的处理者类: 实现具体的处理者类,分别是经理 (ManagerHandler)、总监 (DirectorHandler) 和 CEO (CEOHandler)。每个处理者根据自己的权限处理请求或者将请求传递给下一个处理者。
/** * ManagerHandler 类是具体的处理者,处理经理级别的审批请求。 */ public class ManagerHandler implements ApprovalHandler { private ApprovalHandler nextHandler; // 下一个处理者 @Override public void handleRequest(Request request) { if (request.getAmount().compareTo(BigDecimal.valueOf(1000)) < 0) { // 如果金额小于 1000 元,经理可以直接批准 System.out.println("Manager: Approved for " + request.getName()); } else { // 否则,经理无法处理,传递给下一个处理者 System.out.println("Manager: Unable to approve, forwarding to Director."); nextHandler.handleRequest(request); } } @Override public void setNextHandler(ApprovalHandler nextHandler) { this.nextHandler = nextHandler; } } /** * DirectorHandler 类是具体的处理者,处理总监级别的审批请求。 */ public class DirectorHandler implements ApprovalHandler { private ApprovalHandler nextHandler; // 下一个处理者 @Override public void handleRequest(Request request) { if (request.getAmount().compareTo(BigDecimal.valueOf(1000)) < 0) { // 如果金额小于 1000 元,总监可以直接批准 System.out.println("Director: Approved for " + request.getName()); } else { // 否则,总监无法处理,传递给下一个处理者 System.out.println("Director: Unable to approve, forwarding to CEO."); nextHandler.handleRequest(request); } } @Override public void setNextHandler(ApprovalHandler nextHandler) { this.nextHandler = nextHandler; } } /** * CEOHandler 类是具体的处理者,处理CEO级别的审批请求。 */ public class CEOHandler implements ApprovalHandler { @Override public void handleRequest(Request request) { // CEO作为责任链的末端,直接批准任何金额的请求 System.out.println("CEO: Approved for " + request.getName()); } @Override public void setNextHandler(ApprovalHandler nextHandler) { // CEO作为责任链的末端,不设置下一个处理者 throw new UnsupportedOperationException("CEO is the final authority and does not have a next handler."); } }
-
构建责任链并处理请求: 在客户端代码中,构建责任链并处理请求。请求对象可以是用户输入的金额和购买类型。
/** * Client 类作为客户端代码,创建责任链并模拟处理购买请求。 */ public class Client { public static void main(String[] args) { // 创建责任链:Manager -> Director -> CEO ApprovalHandler manager = new ManagerHandler(); ApprovalHandler director = new DirectorHandler(); ApprovalHandler ceo = new CEOHandler(); manager.setNextHandler(director); director.setNextHandler(ceo); // 模拟用户请求 BigDecimal userAmount = BigDecimal.valueOf(1500); // 用户输入的金额 Request request = new Request("Purchase Request", userAmount); // 开始处理请求 System.out.println("Processing request..."); manager.handleRequest(request); } }
五、责任链模式的应用场景
责任链模式常见于以下场景:
- 审批流程:如报销审批、采购审批等,不同金额级别的审批可以由不同级别的管理者处理,直至最终决策者。
- 日志记录:可以根据日志级别将日志请求传递给不同的处理者(如控制台输出、文件记录、数据库记录等)。
- 权限验证:根据用户的权限等级依次检查是否有权限执行某个操作,直到找到合适的处理者处理请求。
六、小结
责任链模式通过一条责任链上的处理者对象依次尝试处理请求,实现了请求的发送者与接收者之间的解耦,提高了代码的灵活性、可扩展性和复用性。在处理复杂的请求流程、动态确定处理流程或者避免硬编码处理流程时,责任链模式都是一个强大的设计选择。