前言
在软件系统的复杂交互中,请求的处理往往需要跨越多个层级或模块。责任链模式应运而生,它通过将处理对象串联为一条"逻辑流水线",让每个节点专注单一职责,实现请求的自动传递与动态分配。
这种模式如同精密传送带:每个工位(处理者)自主判断能否处理任务,或将其递交给下一环节,既避免了发送者与接收者的强耦合,又赋予系统运行时灵活调整链路的能力。
从网络拦截器的双向过滤到多级审批流程的智能路由,责任链以优雅的链式结构,在权限控制、日志处理、异常兜底等场景中,为复杂逻辑提供了高扩展、低侵入的解决方案,堪称分布式协作的典范设计。
操千曲而后晓声,观千剑而后识器。虐它千百遍方能通晓其真意。
一、基本概念
1.1、本质定义
责任链模式是一种 行为型设计模式,核心思想是:
让
多个对象都有机会处理请求,将这些处理对象连成一条链,请求沿着链传递直到被处理为止
| 概念 | 含义 |
|---|---|
| 处理者链 | 由多个处理者对象组成的链式结构 |
| 请求传递 | 请求从链首开始传递,每个处理者决定处理或传递给下一个 |
| 解耦发送者与接收者 | 发送者不需要知道具体由哪个对象处理请求 |
| 动态扩展 | 可随时增删处理者,灵活调整处理流程 |
1.2、处理者链的本质
核心定义:
由多个 独立处理器对象 构成的链式结构,每个处理器持有下一个处理器的引用,形成 单向或双向处理通道。
结构解析:
// 链表式处理器实现
abstract class Handler {
Handler? _next; // 后继处理器引用
void setNext(Handler next) => _next = next;
void handle(Request request) {
if (canHandle(request)) {
process(request);
} else {
_next?.handle(request); // 链式传递
}
}
bool canHandle(Request request); // 处理判断
void process(Request request); // 处理逻辑
}
动态构建示例:
// 构建三级处理链
final handlerChain = FirstHandler()
..setNext(SecondHandler())
..setNext(FinalHandler());
// 请求处理流程
// Request → FirstHandler → SecondHandler → FinalHandler
关键特性:
- 拓扑结构:支持
线性链、树形链、环形链等多种结构。 - 运行时可变:
动态增删处理器(如热更新过滤规则)。 - 自包含性:每个处理器只需
关注自己的处理逻辑。
1.3、请求传递机制
传递逻辑流程图:
graph TD
A[请求进入] --> B{处理器A能否处理?}
B -- 是 --> C[处理器A处理]
B -- 否 --> D{传递给处理器B?}
D -- 是 --> E[处理器B处理]
D -- 否 --> F[结束传递]
关键处理策略:
| 策略类型 | 实现方式 | 应用场景 |
|---|---|---|
| 短路传递 | 处理器处理后立即终止链条 | 权限校验失败拦截 |
| 全链路传递 | 所有处理器依次处理 | 日志记录链 |
| 条件分支传递 | 根据处理结果选择不同后继处理器 | 多条件审批流程 |
异步传递示例:
// 异步处理器实现
mixin AsyncHandler on Handler {
Future<void> handle(Request request) async {
if (await canHandleAsync(request)) {
await processAsync(request);
} else {
await _next?.handle(request);
}
}
Future<bool> canHandleAsync(Request request);
Future<void> processAsync(Request request);
}
1.4、解耦发送者与接收者
传统耦合模式:
// 发送者直接依赖具体处理器
class Sender {
final HandlerA _handlerA;
final HandlerB _handlerB;
void send(Request request) {
if (_handlerA.canHandle(request)) {
_handlerA.process(request);
} else if (_handlerB.canHandle(request)) {
_handlerB.process(request);
}
}
}
责任链解耦实现:
// 发送者只需知道链入口
class DecoupledSender {
final Handler _chainHead;
void send(Request request) {
_chainHead.handle(request);
}
}
// 配置处理链
final chain = HandlerA()..setNext(HandlerB());
final sender = DecoupledSender(chain);
解耦优势:
- 降低复杂度:发送者代码量减少
90%。 - 提升扩展性:新增处理器
无需修改发送者。 - 增强灵活性:运行时
动态替换处理链。
1.5、动态扩展能力
动态配置示例:
// 可配置处理链管理器
class HandlerChain {
final List<Handler> _handlers = [];
void addHandler(Handler handler) => _handlers.add(handler);
void handle(Request request) {
for (var handler in _handlers) {
if (handler.canHandle(request)) {
handler.process(request);
break; // 短路处理
}
}
}
}
// 运行时动态配置
final chain = HandlerChain()
..addHandler(ValidationHandler())
..addHandler(CacheHandler(expiry: Duration(hours: 1)))
..addHandler(APIClient());
扩展场景:
A/B测试:为不同用户组配置不同处理链。- 灰度发布:逐步添加新处理器到生产环境。
- 故障切换:自动剔除故障处理器并替换。
1.6、概念关联图示
classDiagram
class Client {
+send(Request)
}
class Handler {
<<abstract>>
+setNext(Handler)
+handle(Request)
+canHandle(Request)*
+process(Request)*
}
class ConcreteHandlerA {
+canHandle(Request)
+process(Request)
}
class ConcreteHandlerB {
+canHandle(Request)
+process(Request)
}
Client --> Handler
Handler <|-- ConcreteHandlerA
Handler <|-- ConcreteHandlerB
Handler --> Handler : _next
二、核心价值
从
"硬编码"到"可插拔"的设计跃迁
在软件开发中,代码的扩展性和维护性往往比实现功能本身更具挑战性。责任链模式通过动态链式处理机制,在以下四个维度重构了传统硬编码处理流程,为复杂业务场景提供了优雅解决方案。
3.1、解耦价值:打破 "面条式" 代码结构
3.1.1、传统处理的困境
// 典型耦合代码
Future<Response> fetchData() async {
// 1. 添加日志
logRequest(options);
// 2. 添加认证令牌
addAuthHeader(options);
// 3. 处理加密
encryptBody(options);
// 4. 发送请求
final response = await dio.request(options);
// 5. 解密响应
decryptResponse(response);
// 6. 统一错误处理
handleError(response);
// 7. 记录响应日志
logResponse(response);
}
痛点分析:
- 逻辑
耦合度高,难以复用。 - 新增处理步骤需
修改主流程。 - 错误处理与业务逻辑
混杂。
3.1.2、责任链的解法
通过将每个处理步骤抽象为独立拦截器:
dio.interceptors
..add(LogInterceptor())
..add(AuthInterceptor())
..add(EncryptInterceptor())
..add(ErrorHandlerInterceptor());
实现开闭原则(对扩展开放,对修改关闭)。
3.2、动态编排:实现 "乐高积木" 式流程控制
3.2.1、运行时动态调整
// 根据环境动态加载不同拦截器
if (isProduction) {
dio.interceptors.add(SecurityInterceptor());
} else {
dio.interceptors.add(DebugLoggerInterceptor());
}
3.2.2、流程控制能力对比
| 控制类型 | 责任链模式 | 传统方式 |
|---|---|---|
| 执行顺序 | 动态调整拦截器添加顺序 | 需修改代码逻辑 |
| 条件过滤 | 通过 handler.next 控制传递 | 需增加条件判断分支 |
| 流程终止 | handler.resolve 随时终止 | 需提前 return 或 throw |
3.3、错误处理:从 "try-catch 地狱" 到分层治理
3.3.1、传统错误处理痛点
try {
// 网络请求
} on DioException catch (e) {
if (e.type == timeout) {
// 超时处理
} else if (e.statusCode == 401) {
// 认证失效处理
} else if (e.statusCode >= 500) {
// 服务端错误处理
}
} catch (e) {
// 未知错误
}
问题:错误处理逻辑散落在各处,无法统一管理。
3.3.2、责任链的分层治理
class ErrorInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
// 第一层:网络错误
if (err.type == DioExceptionType.connectionTimeout) {
_handleNetworkError(err);
return;
}
// 第二层:业务错误
final statusCode = err.response?.statusCode;
if (statusCode == 401) {
_refreshTokenAndRetry(err, handler);
return;
}
// 第三层:全局兜底
_showGlobalErrorToast(err);
handler.next(err);
}
}
实现错误类型的金字塔处理模型。
3.4、可观测性:打造请求处理的 "CT 扫描仪"
3.4.1、监控能力扩展
通过组合不同拦截器,可快速实现:
// 性能监控拦截器
class PerformanceInterceptor extends Interceptor {
@override
void onRequest(options, handler) {
options.extra['start_time'] = DateTime.now().millisecondsSinceEpoch;
handler.next(options);
}
@override
void onResponse(response, handler) {
final duration = DateTime.now().millisecondsSinceEpoch -
response.requestOptions.extra['start_time'];
Analytics.logApiDuration(response.uri.path, duration);
handler.next(response);
}
}
// 流量统计拦截器
class TrafficMonitorInterceptor extends Interceptor {
@override
void onResponse(response, handler) {
final size = utf8.encode(jsonEncode(response.data)).length;
TrafficMonitor.record(response.uri.host, size);
handler.next(response);
}
}
3.4.2、观测维度
| 拦截器类型 | 可观测维度 | 输出形式 |
|---|---|---|
PerformanceInterceptor | 接口耗时 | 折线图/百分位数统计 |
TrafficMonitorInterceptor | 网络流量 | 环形占比图/日环比数据 |
ErrorAlertInterceptor | 异常类型分布 | 饼图/TOP N 报警 |
CacheHitInterceptor | 缓存命中率 | 热力图/时间段对比 |
3.5、本质价值:从 "流程" 到 "生态" 的升级
责任链模式的终极价值不在于解决某个具体技术问题,而在于构建了一个可扩展的请求处理生态系统。这种设计使得:
- 1、新人快速上手:通过拦截器文档了解全局处理流程。
- 2、架构持续演进:新功能通过拦截器形式无缝接入。
- 3、能力动态组合:针对不同场景组装个性化处理链。
- 4、监控全面覆盖:通过拦截器实现全链路可观测性。
正如在 Dio 中的实践所示,当责任链模式与拦截器机制结合时,网络请求处理不再是简单的数据传输,而是进化为一个充满可能性的开放平台。这才是现代框架设计的精髓所在。
三、核心组件实现
3.1、抽象处理者(Handler)
/// 链表式处理器实现
abstract class Handler {
/// 链中的下一个处理者
Handler? _nextHandler;
/// 设置下一个处理者
Handler setNext(Handler handler) {
_nextHandler = handler;
return handler; // 支持链式调用
}
/// 处理请求的模板方法
void handleRequest(String request) {
if (canHandle(request)) {
doHandle(request);
} else if (_nextHandler != null) {
_nextHandler!.handleRequest(request);
} else {
defaultHandler(request);
}
}
/// 判断是否能处理请求(由子类实现)
bool canHandle(String request);
/// 具体处理逻辑(由子类实现)
void doHandle(String request);
/// 默认处理方式
void defaultHandler(String request) {
print("⚠️ 没有处理者能处理请求:$request");
}
}
3.2、具体处理者
/// 处理者A:处理长度<=5的请求
class LengthHandler extends Handler {
@override
bool canHandle(String request) => request.length <= 5;
@override
void doHandle(String request) {
print("🟢 LengthHandler 处理请求:'$request' (长度=${request.length})");
}
}
/// 处理者B:处理包含"VIP"的请求
class VIPHandler extends Handler {
@override
bool canHandle(String request) => request.contains("VIP");
@override
void doHandle(String request) {
print("🔵 VIPHandler 处理特殊请求:'$request'");
}
}
/// 处理者C:处理数字请求
class NumberHandler extends Handler {
@override
bool canHandle(String request) => RegExp(r'^\d+$').hasMatch(request);
@override
void doHandle(String request) {
print("🟡 NumberHandler 处理数字请求:'$request'");
}
}
3.3、客户端使用
void main() {
/// 1. 创建处理链
final handlerChain = LengthHandler()
..setNext(VIPHandler())
..setNext(NumberHandler());
/// 2. 发送不同请求
const requests = ['123', 'HelloVIP', '567890', 'TooLongRequest', 'VIP123'];
for (final request in requests) {
print("\n🚀 发送请求:'$request'");
handlerChain.handleRequest(request);
}
}
输出结果:
🚀 发送请求:'123'
🟢 LengthHandler 处理请求:'123' (长度=3)
🚀 发送请求:'HelloVIP'
⚠️ 没有处理者能处理请求:HelloVIP
🚀 发送请求:'567890'
🟡 NumberHandler 处理数字请求:'567890'
🚀 发送请求:'TooLongRequest'
⚠️ 没有处理者能处理请求:TooLongRequest
🚀 发送请求:'VIP123'
⚠️ 没有处理者能处理请求:VIP123
四、模式运作流程图
sequenceDiagram
participant Client
participant HandlerA
participant HandlerB
participant HandlerC
Client->>HandlerA: 发送请求
HandlerA->>HandlerA: 能否处理?
alt 能处理
HandlerA-->>Client: 处理完成
else 不能处理
HandlerA->>HandlerB: 传递请求
HandlerB->>HandlerB: 能否处理?
alt 能处理
HandlerB-->>Client: 处理完成
else 不能处理
HandlerB->>HandlerC: 传递请求
HandlerC->>HandlerC: 能否处理?
alt 能处理
HandlerC-->>Client: 处理完成
else 不能处理
HandlerC-->>Client: 无法处理
end
end
end
五、模式核心特点
- 1、链式结构
- 处理者通过
setNext方法形成链条。 - 请求沿链传递,直到被处理或到达链尾。
- 处理者通过
- 2、处理判断逻辑
- 每个处理者通过
_canHandle决定是否处理。 - 处理者之间完全解耦,只需关注自己的处理范围。
- 每个处理者通过
- 3、扩展性
- 新增处理者只需继承
Handler并实现两个方法。 - 无需修改已有代码,符合开闭原则。
- 新增处理者只需继承
六、进阶应用
6.1、典型使用场景
| 场景 | 案例实现 |
|---|---|
| 网络请求拦截 | Dio拦截器、OkHttp拦截器 |
| 事件处理系统 | GUI事件传播(如Flutter手势竞争) |
| 工作流审批系统 | 多级审批流程(经理→总监→CEO) |
| 日志处理管道 | 日志级别过滤 → 格式转换 → 输出目标选择 |
| 异常处理系统 | 本地缓存 → 网络重试 → 全局降级 |
6.2、审批系统
abstract class Approver {
Approver? next;
bool handle(ApprovalRequest request) {
if (_canHandle(request)) {
print("✅ [$runtimeType] 批准金额:$${request.amount.toStringAsFixed(2)}");
return true;
}
if (next != null) {
return next!.handle(request);
}
print("❌ 金额 $${request.amount} 超出所有审批人权限");
return false;
}
bool _canHandle(ApprovalRequest request); // 抽象方法
}
// ---------- 具体审批人 ----------
class Manager extends Approver {
@override
bool _canHandle(ApprovalRequest request) => request.amount <= 10000;
}
class Director extends Approver {
@override
bool _canHandle(ApprovalRequest request) => request.amount <= 50000;
}
class CEO extends Approver {
@override
bool _canHandle(ApprovalRequest request) => true; // 无金额限制
}
class ApprovalRequest {
final double amount;
ApprovalRequest(this.amount);
}
void main() {
// 构建审批链:经理 → 总监 → CEO
final manager = Manager();
final director = Director();
final ceo = CEO();
manager.next = director;
director.next = ceo;
// 测试用例
final testAmounts = [8000.0, 25000.0, 100000.0];
for (final amount in testAmounts) {
print("\n=== 处理申请:$${amount.toStringAsFixed(2)} ===");
manager.handle(ApprovalRequest(amount));
}
}
输出结果:
=== 处理申请:$8000.00 ===
✅ [Manager] 批准金额:$8000.00
=== 处理申请:$25000.00 ===
✅ [Director] 批准金额:$25000.00
=== 处理申请:$100000.00 ===
✅ [CEO] 批准金额:$100000.00
6.3、网络请求过滤
import 'dart:io';
import 'dart:convert';
/// ------------------ 核心抽象定义 ------------------
abstract class Handler {
Handler? _next;
Handler setNext(Handler next) {
_next = next;
return this;
}
Future<Response> handle(Request request) async {
if (await canHandle(request)) {
return await process(request);
} else if (_next != null) {
return await _next!.handle(request);
} else {
return Response(404, 'Not Found');
}
}
bool canHandle(Request request);
Future<Response> process(Request request);
}
/// ------------------ 具体模型定义 ------------------
class Request {
final String method;
final Uri uri;
final Map<String, String> headers;
Request.get(this.uri, {this.headers = const {}}) : method = 'GET';
}
class Response {
final int statusCode;
final String body;
Response(this.statusCode, this.body);
}
/// ------------------ 具体处理者实现 ------------------
class LogHandler extends Handler {
@override
bool canHandle(Request request) => true;
@override
Future<Response> process(Request request) async {
final stopwatch = Stopwatch()..start();
print('📥 请求开始: ${request.uri}');
try {
final response = await _next?.handle(request) ?? Response(404, 'Not Found');
print('📤 请求完成 (${stopwatch.elapsedMilliseconds}ms)');
return response;
} catch (e) {
print('💥 请求异常: $e');
return Response(500, 'Server Error');
}
}
}
class AuthHandler extends Handler {
final String _validToken;
AuthHandler(this._validToken);
@override
bool canHandle(Request request) {
return request.headers.containsKey('Authorization');
}
@override
Future<Response> process(Request request) async {
final token = request.headers['Authorization']!.split(' ').last;
if (token != _validToken) {
return Response(401, 'Unauthorized');
}
print('🔑 认证通过');
return await _next?.handle(request) ?? Response(404, 'Not Found');
}
}
class HttpClientHandler extends Handler {
final HttpClient _client = HttpClient();
@override
bool canHandle(Request request) => true;
@override
Future<Response> process(Request request) async {
try {
final req = await _client.getUrl(request.uri);
request.headers.forEach((key, value) => req.headers.add(key, value));
final res = await req.close();
final body = await res.transform(utf8.decoder).join();
return Response(res.statusCode, body);
} finally {
_client.close();
}
}
}
// ------------------ 使用示例 ------------------
void main() async {
// 构建处理链
final logHandler = LogHandler();
final authHandler = AuthHandler('valid_token_123');
final httpClientHandler = HttpClientHandler();
logHandler.setNext(authHandler);
authHandler.setNext(httpClientHandler);
// 测试用例
final testCases = [
Request.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1')),
Request.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
headers: {'Authorization': 'Bearer valid_token_123'}
),
Request.get(Uri.parse('https://invalid.url'))
];
for (var request in testCases) {
print('\n${'=' * 40}');
print('测试请求: ${request.uri}');
final response = await logHandler.handle(request);
print('状态码: ${response.statusCode}');
print('响应长度: ${response.body.length}字符');
}
}
输出结果:
========================================
测试请求: https://jsonplaceholder.typicode.com/posts/1
📥 请求开始: https://jsonplaceholder.typicode.com/posts/1
📤 请求完成 (736ms)
状态码: 200
响应长度: 292字符
========================================
测试请求: https://jsonplaceholder.typicode.com/posts/1
📥 请求开始: https://jsonplaceholder.typicode.com/posts/1
🔑 认证通过
💥 请求异常: Bad state: Client is closed
状态码: 500
响应长度: 12字符
========================================
测试请求: https://invalid.url
📥 请求开始: https://invalid.url
💥 请求异常: Bad state: Client is closed
状态码: 500
响应长度: 12字符
七、模式优缺点对比
| 优点 | 缺点 |
|---|---|
| ✅ 降低耦合度:请求发送者无需知道处理细节 | ❌ 请求可能未被处理(需兜底逻辑) |
| ✅ 动态调整处理流程 | ❌ 长链影响性能 |
| ✅ 符合单一职责原则 | ❌ 调试难度增加 |
| ✅ 方便扩展新处理者 | ❌ 可能产生循环调用 |
八、最佳实践建议
1、控制链长度
- 建议不超过
5个处理者。 - 复杂场景可
分级处理。
2、设置兜底处理
class DefaultHandler extends Handler {
@override
bool _canHandle(String request) => true; // 最后执行
@override
void _doHandle(String request) {
print("⚠️ 默认处理:$request");
}
}
3、性能优化
// 缓存处理能力判断
final _cache = <String, bool>{};
@override
bool _canHandle(String request) =>
_cache.putIfAbsent(request, () => _calculateCanHandle(request));
九、总结
通过深入理解责任链模式,我们可以更好地设计可扩展的中间件系统。关键在于:
- 1、合理划分处理边界。
- 2、明确传递/中断策略。
- 3、谨慎处理异步操作。
- 4、建立完善的监控机制。
该模式在网络框架、工作流引擎、事件处理系统中广泛应用,是构建灵活系统架构的重要工具之一。
欢迎一键四连(
关注+点赞+收藏+评论)