设计模式——责任链设计模式(行为型)
摘要
责任链设计模式是一种行为型设计模式,旨在将请求的发送者与接收者解耦,通过多个处理器对象按链式结构依次处理请求,直到某个处理器处理为止。它包含抽象处理者、具体处理者和客户端等核心角色。该模式适用于多个对象可能处理请求的场景,如风控系统中的贷款申请流程,通过链式组合处理整个流程。实现方式包括链式引用和集合遍历等,适用于信贷申请风控校验等实际应用。
1. 责任链设计模式定义
责任链设计模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许多个处理器对象都有机会处理请求,避免请求的发送者与接收者之间的耦合关系。这些处理器按照链式结构连接,每个处理器决定是否处理请求,或将其传递给链上的下一个处理器。
1.1.1. ✅ 责任链设计模式定义要点:
项目 | 内容 |
目的 | 将请求的发送者与接收者解耦,让多个对象有机会处理请求。 |
结构 | 每个处理者持有对下一个处理者的引用,形成链式结构。 |
核心机制 | 请求沿链传递,直到被某个处理者处理为止。 |
关键点 | 不关心请求由谁处理,处理器职责明确,链条可灵活组合。 |
1.1.2. ✅ UML 类图核心角色:
- Handler(抽象处理者):定义处理请求的接口,维护下一个处理者引用。
- ConcreteHandler(具体处理者):实现处理逻辑,判断是否处理请求,否则传递。
- Client(客户端):构建责任链并发起请求。
1.1.3. ✅ 示例场景说明(以风控为例):
风控系统中,一条贷款申请请求需要依次经过:
黑名单检查 → 信用评分检查 → 欺诈风险检查 → 额度判断
每个检查环节都是一个责任节点,最终链式组合处理整个申请流程。
2. 责任链设计模式结构
2.1. 责任链设计模式类图
- 处理者 (Handler) 声明了所有具体处理者的通用接口。
- 基础处理者 (Base Handler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。
- 具体处理者 (Concrete Handlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。
- 客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。
3. 责任链设计模式实现方式
责任链设计模式的实现方式有两种主要形式:链式引用方式 和 集合遍历方式。在 Java 和 Spring 项目中,两种方式都可以灵活使用,以下是详细实现说明:
3.1. ✅ 链式引用方式(经典责任链)
3.1.1. 定义抽象处理器
public abstract class RiskHandler {protected RiskHandler next;public void setNext(RiskHandler next) {this.next = next;}public void handle(Request request) {if (doHandle(request) && next != null) {next.handle(request);}}protected abstract boolean doHandle(Request request);
}
3.1.2. 实现具体处理器
@Component
public class BlacklistHandler extends RiskHandler {@Overrideprotected boolean doHandle(Request request) {System.out.println("黑名单校验");// 模拟通过return true;}
}@Component
public class CreditScoreHandler extends RiskHandler {@Overrideprotected boolean doHandle(Request request) {System.out.println("信用评分校验");return true;}
}
3.1.3. 构造责任链(可由 Spring 初始化)
@Component
public class RiskChainBuilder {@Autowiredprivate BlacklistHandler blacklistHandler;@Autowiredprivate CreditScoreHandler creditScoreHandler;@PostConstructpublic void init() {blacklistHandler.setNext(creditScoreHandler);// 可继续设置下一个}public RiskHandler getChain() {return blacklistHandler;}
}
3.2. ✅ 集合遍历方式(策略+责任链)
这种方式更适合使用 Spring 管理 Bean。
3.2.1. 定义统一接口
public interface RiskHandler {boolean handle(Request request);
}
3.2.2. 实现多个处理器(用注解自动注入)
@Component
public class BlacklistHandler implements RiskHandler {public boolean handle(Request request) {System.out.println("黑名单处理");return true;}
}@Component
public class CreditHandler implements RiskHandler {public boolean handle(Request request) {System.out.println("信用处理");return true;}
}
3.2.3. 责任链执行器
@Component
public class RiskChainExecutor {@Autowiredprivate List<RiskHandler> handlers;public void process(Request request) {for (RiskHandler handler : handlers) {if (!handler.handle(request)) {break; // 拦截处理}}}
}
3.3. ✅ 责任链实现方式总结
项目 | 链式引用方式 | 集合遍历方式 |
Spring友好 | 较差,需要手动串联 | 非常友好,自动注入 List |
动态配置顺序 | 不方便(写死在代码) | 可通过 |
灵活性 | 灵活,可动态组合链 | 更适合顺序一致、处理流程清晰 |
推荐程度 | 简单链条推荐使用 | 企业级风控强烈推荐 |
4. 责任链设计模式适合场景
4.1. ✅ 适合使用责任链设计模式的场景
场景 | 说明 |
多个对象可以处理同一请求 | 请求的处理者不唯一,多个处理器具备处理能力。 |
处理逻辑具有先后顺序且可拆分 | 如风控流程、审批流程、日志处理、事件流转等。 |
希望动态添加或修改处理逻辑链 | 支持运行时动态组合处理器链条,提高灵活性。 |
解耦请求与处理器之间的关系 | 请求发送者无需知道谁会处理,只需交给链处理。 |
处理节点对请求是否继续传递有决策权 | 允许部分处理节点终止请求,如认证失败即停止。 |
4.2. ❌ 不适合使用责任链设计模式的场景
场景 | 原因 |
处理流程固定,结构简单 | 使用责任链会增加结构复杂度,得不偿失。 |
必须同时执行所有处理逻辑,不允许中断 | 责任链是短路模型(遇到失败可中断),不适合要求“全部执行”的场景。 |
处理者之间高度耦合或依赖上下文共享 | 处理节点应独立,依赖过多会降低可维护性。 |
对性能要求极高、链条很长 | 每次请求都需遍历链条,可能带来额外性能损耗。 |
请求必须同时由多个处理器并行处理 | 责任链是串行模式,不适合并行处理场景。 |
4.3. 📌 实际应用建议
使用责任链的条件 | 建议 |
节点解耦 + 处理器独立 + 顺序可变 | ✅ 可考虑使用 |
所有处理器必须全执行,顺序固定 | ❌ 不推荐,改用责任集(全执行)或责任调度中心 |
所有逻辑都写死在 if-else 中 | ✅ 可用责任链重构,提高扩展性和可维护性 |
5. 责任链设计模式实战示例
5.1. ✅ 应用场景:信贷申请风控校验
系统在用户提交借款申请时,需要依次执行以下校验逻辑(处理链):
- 黑名单校验
- 实名认证校验
- 信用评分校验
5.2. 🧩 请求对象
public class LoanRequest {private String userId;private String name;private int age;// 其他信息// getter/setter省略
}
5.3. 🧩 风控处理器接口
public interface RiskHandler {/*** 返回 true 表示通过校验,继续执行后续处理器;false 表示终止处理。*/boolean handle(LoanRequest request);
}
5.4. 🧩 风控处理器实现(举例4个)
5.4.1. 🔹 黑名单校验器
@Component
@Order(1)
public class BlacklistHandler implements RiskHandler {@Overridepublic boolean handle(LoanRequest request) {System.out.println("黑名单校验: " + request.getUserId());// 假设用户不在黑名单中return true;}
}
5.4.2. 🔹 实名认证校验器
@Component
@Order(2)
public class RealNameHandler implements RiskHandler {@Overridepublic boolean handle(LoanRequest request) {System.out.println("实名认证校验: " + request.getName());return true;}
}
5.4.3. 🔹 信用评分校验器
@Component
@Order(3)
public class CreditScoreHandler implements RiskHandler {@Overridepublic boolean handle(LoanRequest request) {System.out.println("信用评分校验: " + request.getUserId());return true;}
}
5.4.4. 🔹 反欺诈规则校验器
@Component
@Order(4)
public class AntiFraudHandler implements RiskHandler {@Overridepublic boolean handle(LoanRequest request) {System.out.println("反欺诈校验: " + request.getUserId());return true;}
}
5.5. 🧩 风控责任链执行器(接口变实现遍历)
@Component
public class RiskCheckExecutor {@Autowiredprivate List<RiskHandler> handlers;public boolean execute(LoanRequest request) {for (RiskHandler handler : handlers) {if (!handler.handle(request)) {System.out.println("风控拦截,终止流程");return false;}}System.out.println("所有风控校验通过");return true;}
}
@Order
确保处理器执行顺序一致。
5.6. 🧩 测试调用示例(如用于 Controller)
@RestController
@RequestMapping("/loan")
public class LoanController {@Autowiredprivate RiskCheckExecutor executor;@PostMapping("/apply")public ResponseEntity<String> apply(@RequestBody LoanRequest request) {boolean pass = executor.execute(request);if (pass) {return ResponseEntity.ok("风控通过,进入审批");} else {return ResponseEntity.status(HttpStatus.FORBIDDEN).body("风控未通过");}}
}
5.7. ✅ 项目示例总结
特性 | 说明 |
注解注入 | 使用 |
避免构造函数 | 所有注入均为字段注入,无需构造器方式 |
解耦结构 | 每个处理器职责单一,互不干扰 |
可扩展性 | 增加校验逻辑仅需新增实现类并加上 |
6. 责任链设计模式思考
博文参考
- https://github.com/guanguans/design-patterns-for-humans-cn