责任链模式
大约 12 分钟约 3676 字
责任链模式
简介
责任链(Chain of Responsibility)将请求沿着处理者链传递,直到有一个处理者能够处理。理解责任链模式,有助于构建可灵活组合的请求处理管道。
责任链模式的思想类似于现实生活中的"逐级上报":当你向基层员工提出一个请求,如果他没有权限处理,就会把请求转给上级;上级也处理不了就继续上报,直到有人能处理为止。在软件中,这种模式被广泛应用于审批流程、异常处理、中间件管道、事件分发等场景。
GoF 对责任链模式的定义为:"避免请求发送者与接收者之间的耦合,让多个对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。"
特点
结构分析
UML 类图
+--------------------+
| Handler | <-- 抽象处理者
+--------------------+
| #Next: Handler? |
| +SetNext(): Handler|
| +Handle(request) |
+--------------------+
^
|
+-------------+-------------+
| | |
+--------+ +----------+ +----------+
| TeamLead| | Manager | | Director |
+--------+ +----------+ +----------+
| Handle()| | Handle() | | Handle() |
+--------+ +----------+ +----------+请求传递流程
Client -> [TeamLead] -> [Manager] -> [Director]
| | |
Amount<=1000 Amount<=10000 Amount<=100000
| | |
处理或传递 处理或传递 处理或拒绝实现
审批流程
public abstract class Approver
{
protected Approver? Next { get; private set; }
public string Name { get; }
protected Approver(string name) => Name = name;
public Approver SetNext(Approver next) { Next = next; return next; }
public abstract void HandleRequest(PurchaseRequest request);
}
public record PurchaseRequest(string Item, decimal Amount);
public class TeamLead : Approver
{
public TeamLead() : base("组长") { }
public override void HandleRequest(PurchaseRequest req)
{
if (req.Amount <= 1000) Console.WriteLine($"{Name} 审批: {req.Item} Y{req.Amount}");
else Next?.HandleRequest(req);
}
}
public class Manager : Approver
{
public Manager() : base("经理") { }
public override void HandleRequest(PurchaseRequest req)
{
if (req.Amount <= 10000) Console.WriteLine($"{Name} 审批: {req.Item} Y{req.Amount}");
else Next?.HandleRequest(req);
}
}
public class Director : Approver
{
public Director() : base("总监") { }
public override void HandleRequest(PurchaseRequest req)
{
if (req.Amount <= 100000) Console.WriteLine($"{Name} 审批: {req.Item} Y{req.Amount}");
else Console.WriteLine($"X 金额过大({req.Amount}),需董事会审批");
}
}
// 使用 — 构建链
var lead = new TeamLead();
lead.SetNext(new Manager()).SetNext(new Director());
lead.HandleRequest(new PurchaseRequest("键盘", 500)); // 组长审批
lead.HandleRequest(new PurchaseRequest("显示器", 5000)); // 经理审批
lead.HandleRequest(new PurchaseRequest("服务器", 80000)); // 总监审批中间件管道(ASP.NET Core 风格)
public delegate Task RequestHandler(HttpContext context);
public class PipelineBuilder
{
private readonly List<Func<RequestHandler, RequestHandler>> _middlewares = new();
public PipelineBuilder Use(Func<RequestHandler, RequestHandler> middleware)
{
_middlewares.Add(middleware);
return this;
}
public RequestHandler Build()
{
RequestHandler handler = ctx => { Console.WriteLine("终端处理"); return Task.CompletedTask; };
for (int i = _middlewares.Count - 1; i >= 0; i--)
handler = _middlewares[i](handler);
return handler;
}
}
public record HttpContext(string Path, string Method, Dictionary<string, string> Headers);
// 使用
var app = new PipelineBuilder()
.Use(next => async ctx =>
{
Console.WriteLine($"[日志] {ctx.Method} {ctx.Path}");
await next(ctx);
})
.Use(next => async ctx =>
{
if (!ctx.Headers.TryGetValue("Authorization", out var _))
{ Console.WriteLine("[认证] 401 未授权"); return; }
await next(ctx);
})
.Use(next => async ctx =>
{
Console.WriteLine("[缓存] 检查缓存");
await next(ctx);
Console.WriteLine("[缓存] 写入缓存");
})
.Build();
await app(new HttpContext("/api/users", "GET", new() { { "Authorization", "Bearer xxx" } }));事件处理链
public interface IEventHandler
{
IEventHandler? Next { get; set; }
Task<bool> HandleAsync(DomainEvent evt);
}
public abstract class EventHandlerBase : IEventHandler
{
public IEventHandler? Next { get; set; }
public async Task<bool> HandleAsync(DomainEvent evt)
{
var handled = await DoHandle(evt);
if (!handled && Next != null) return await Next.HandleAsync(evt);
return handled;
}
protected abstract Task<bool> DoHandle(DomainEvent evt);
}
public record DomainEvent(string Type, string Payload);
public class ValidationHandler : EventHandlerBase
{
protected override Task<bool> DoHandle(DomainEvent evt)
{
if (string.IsNullOrEmpty(evt.Payload)) { Console.WriteLine("验证失败: 空数据"); return Task.FromResult(true); }
Console.WriteLine("验证通过"); return Task.FromResult(false);
}
}
public class LoggingHandler : EventHandlerBase
{
protected override Task<bool> DoHandle(DomainEvent evt)
{
Console.WriteLine($"日志: {evt.Type} - {evt.Payload}"); return Task.FromResult(false);
}
}
public class PersistenceHandler : EventHandlerBase
{
protected override Task<bool> DoHandle(DomainEvent evt)
{
Console.WriteLine($"持久化: {evt.Type}"); return Task.FromResult(true);
}
}
// 构建链
var chain = new ValidationHandler { Next = new LoggingHandler { Next = new PersistenceHandler() } };
await chain.HandleAsync(new DomainEvent("OrderCreated", """{"orderId": 123}"""));实战:日志分级处理链
在日志系统中,不同级别的日志需要不同的处理策略。使用责任链模式可以灵活地组合日志处理器。
public class LogEntry
{
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
public LogLevel Level { get; init; }
public string Message { get; init; } = "";
public string? Source { get; init; }
}
public enum LogLevel { Debug, Info, Warning, Error, Fatal }
public abstract class LogHandler
{
protected LogHandler? Next { get; private set; }
public LogHandler SetNext(LogHandler next) { Next = next; return next; }
public void Handle(LogEntry entry)
{
if (CanHandle(entry))
{
Process(entry);
}
Next?.Handle(entry);
}
protected abstract bool CanHandle(LogEntry entry);
protected abstract void Process(LogEntry entry);
}
public class FatalErrorHandler : LogHandler
{
protected override bool CanHandle(LogEntry entry) => entry.Level >= LogLevel.Fatal;
protected override void Process(LogEntry entry)
{
Console.WriteLine($"[致命] {entry.Timestamp:HH:mm:ss} {entry.Message}");
// 触发告警通知
SendAlert(entry);
}
private void SendAlert(LogEntry entry)
=> Console.WriteLine($" -> 发送告警邮件: {entry.Message}");
}
public class ErrorHandler : LogHandler
{
protected override bool CanHandle(LogEntry entry) => entry.Level >= LogLevel.Error;
protected override void Process(LogEntry entry)
{
Console.WriteLine($"[错误] {entry.Timestamp:HH:mm:ss} [{entry.Source}] {entry.Message}");
// 写入错误日志文件
WriteToFile(entry);
}
private void WriteToFile(LogEntry entry)
=> Console.WriteLine($" -> 写入 error.log");
}
public class InfoHandler : LogHandler
{
protected override bool CanHandle(LogEntry entry) => entry.Level >= LogLevel.Info;
protected override void Process(LogEntry entry)
{
Console.WriteLine($"[信息] {entry.Timestamp:HH:mm:ss} {entry.Message}");
}
}
// 构建链 — 每个日志都经过所有处理器
var logChain = new InfoHandler();
logChain.SetNext(new ErrorHandler()).SetNext(new FatalErrorHandler());
logChain.Handle(new LogEntry { Level = LogLevel.Info, Message = "应用启动" });
logChain.Handle(new LogEntry { Level = LogLevel.Error, Source = "PaymentService", Message = "支付超时" });
logChain.Handle(new LogEntry { Level = LogLevel.Fatal, Message = "数据库连接失败" });实战:基于泛型的责任链构建器
public class ChainBuilder<TRequest>
{
private readonly List<Func<Func<TRequest, Task<bool>>, Func<TRequest, Task<bool>>>> _handlers = new();
public ChainBuilder<TRequest> AddHandler(Func<TRequest, Task<bool>> handler)
{
_handlers.Add(next => async req =>
{
var handled = await handler(req);
return handled || await next(req);
});
return this;
}
public ChainBuilder<TRequest> AddHandler<THandler>() where THandler : IHandler<TRequest>, new()
{
return AddHandler(new THandler().HandleAsync);
}
public Func<TRequest, Task<bool>> Build()
{
Func<TRequest, Task<bool>> terminal = _ => Task.FromResult(false);
for (int i = _handlers.Count - 1; i >= 0; i--)
terminal = _handlers[i](terminal);
return terminal;
}
}
public interface IHandler<TRequest>
{
Task<bool> HandleAsync(TRequest request);
}
// 使用
var approvalChain = new ChainBuilder<PurchaseRequest>()
.AddHandler<TeamLeadHandler>()
.AddHandler<ManagerHandler>()
.AddHandler<DirectorHandler>()
.Build();
await approvalChain(new PurchaseRequest("服务器", 50000));实战:异常处理责任链
异常处理是责任链的经典应用场景。不同类型的异常由不同处理器处理,未处理的异常沿链传递。
public abstract class Exceptionhandler
{
protected ExceptionHandler? Next { get; private set; }
public ExceptionHandler SetNext(ExceptionHandler next) { Next = next; return next; }
public async Task HandleAsync(Exception ex)
{
if (CanHandle(ex))
{
await DoHandleAsync(ex);
}
else
{
if (Next is null)
throw new InvalidOperationException($"无处理器可处理异常: {ex.GetType().Name}", ex);
await Next.HandleAsync(ex);
}
}
protected abstract bool CanHandle(Exception ex);
protected abstract Task DoHandleAsync(Exception ex);
}
public class ValidationExceptionHandler : ExceptionHandler
{
protected override bool CanHandle(Exception ex) => ex is ArgumentException or FormatException;
protected override Task DoHandleAsync(Exception ex)
{
Console.WriteLine($"[验证异常] {ex.Message}");
return Task.CompletedTask;
}
}
public class TimeoutExceptionHandler : ExceptionHandler
{
protected override bool CanHandle(Exception ex) => ex is TimeoutException or TaskCanceledException;
protected override Task DoHandleAsync(Exception ex)
{
Console.WriteLine($"[超时异常] {ex.Message} — 建议重试");
return Task.CompletedTask;
}
}
public class DatabaseExceptionHandler : ExceptionHandler
{
protected override bool CanHandle(Exception ex) => ex.GetType().Name.Contains("Sql") || ex.GetType().Name.Contains("Db");
protected override Task DoHandleAsync(Exception ex)
{
Console.WriteLine($"[数据库异常] {ex.Message} — 触发告警");
return Task.CompletedTask;
}
}
public class FallbackExceptionHandler : ExceptionHandler
{
protected override bool CanHandle(Exception ex) => true; // 兜底
protected override Task DoHandleAsync(Exception ex)
{
Console.WriteLine($"[未知异常] {ex.GetType().Name}: {ex.Message}");
return Task.CompletedTask;
}
}
// 构建链
var handlerChain = new ValidationExceptionHandler();
handlerChain.SetNext(new TimeoutExceptionHandler())
.SetNext(new DatabaseExceptionHandler())
.SetNext(new FallbackExceptionHandler()); // 兜底处理
await handlerChain.HandleAsync(new ArgumentException("参数不能为空"));
await handlerChain.HandleAsync(new TimeoutException("请求超时"));
await handlerChain.HandleAsync(new NullReferenceException("意外空引用"));实战:请求校验管道
在 Web API 中,请求经过多个校验步骤,每个步骤可以决定是否放行或拒绝。
public abstract class RequestValidator
{
protected RequestValidator? Next { get; private set; }
public RequestValidator SetNext(RequestValidator next) { Next = next; return next; }
public async Task<ValidationResult> ValidateAsync(ApiRequest request)
{
var result = await DoValidateAsync(request);
if (!result.IsValid)
return result;
if (Next != null)
return await Next.ValidateAsync(request);
return ValidationResult.Success();
}
protected abstract Task<ValidationResult> DoValidateAsync(ApiRequest request);
}
public record ValidationResult(bool IsValid, string? ErrorMessage = null)
{
public static ValidationResult Success() => new(true);
public static ValidationResult Fail(string message) => new(false, message);
}
public record ApiRequest(string Path, string Method, string? Token, string? Body, Dictionary<string, string> Headers);
// 身份验证
public class AuthValidator : RequestValidator
{
protected override Task<ValidationResult> DoValidateAsync(ApiRequest request)
{
if (string.IsNullOrEmpty(request.Token))
return Task.FromResult(ValidationResult.Fail("缺少认证令牌"));
if (!request.Token.StartsWith("Bearer "))
return Task.FromResult(ValidationResult.Fail("令牌格式不正确"));
return Task.FromResult(ValidationResult.Success());
}
}
// 权限检查
public class PermissionValidator : RequestValidator
{
private readonly HashSet<string> _writeMethods = new() { "POST", "PUT", "DELETE" };
protected override Task<ValidationResult> DoValidateAsync(ApiRequest request)
{
// 假设只读令牌不能执行写操作
if (_writeMethods.Contains(request.Method) && request.Token?.Contains("readonly") == true)
return Task.FromResult(ValidationResult.Fail("只读令牌无权执行写操作"));
return Task.FromResult(ValidationResult.Success());
}
}
// 请求体校验
public class BodyValidator : RequestValidator
{
protected override Task<ValidationResult> DoValidateAsync(ApiRequest request)
{
if (request.Method == "POST" && string.IsNullOrEmpty(request.Body))
return Task.FromResult(ValidationResult.Fail("POST 请求必须有请求体"));
if (request.Body?.Length > 1_000_000)
return Task.FromResult(ValidationResult.Fail("请求体超过 1MB 限制"));
return Task.FromResult(ValidationResult.Success());
}
}
// 频率限制
public class RateLimitValidator : RequestValidator
{
private readonly Dictionary<string, DateTime> _lastRequest = new();
private readonly TimeSpan _minInterval = TimeSpan.FromMilliseconds(100);
protected override Task<ValidationResult> DoValidateAsync(ApiRequest request)
{
var key = $"{request.Token}:{request.Path}";
if (_lastRequest.TryGetValue(key, out var lastTime))
{
if (DateTime.UtcNow - lastTime < _minInterval)
return Task.FromResult(ValidationResult.Fail("请求过于频繁"));
}
_lastRequest[key] = DateTime.UtcNow;
return Task.FromResult(ValidationResult.Success());
}
}
// 构建校验管道
var validator = new AuthValidator();
validator.SetNext(new PermissionValidator())
.SetNext(new BodyValidator())
.SetNext(new RateLimitValidator());
var testRequest = new ApiRequest("/api/users", "POST", "Bearer xxx", """{"name":"test"}""", new());
var result = await validator.ValidateAsync(testRequest);
Console.WriteLine(result.IsValid ? "校验通过" : $"校验失败: {result.ErrorMessage}");责任链 vs 管道模式 vs 命令模式
责任链模式 管道模式 命令模式
+--------+ +--------+ +--------+
| 请求沿 | | 数据沿 | | 请求封 |
| 链传递 | | 管道流 | | 装为命 |
+--------+ +--------+ +--------+
| 某个 | | 每个 | | 可排队 |
| 处理者 | | 阶段 | | 可撤销 |
| 处理 | | 都处理 | | 可存储 |
+--------+ +--------+ +--------+
| 不保证 | | 保证 | | 保证 |
| 处理 | | 全部 | | 执行 |
+--------+ +--------+ +--------+责任链的两种传递模式
责任链模式在实际应用中存在两种常见的传递模式,理解它们的差异对正确使用非常重要。
// 模式一:纯责任链 — 找到第一个能处理的就停止
// 适用场景:审批流程(只需一个人审批)
public abstract class PureHandler
{
protected PureHandler? Next { get; private set; }
public PureHandler SetNext(PureHandler next) { Next = next; return next; }
public void Handle(Request request)
{
if (CanHandle(request))
DoHandle(request);
else
Next?.Handle(request);
}
protected abstract bool CanHandle(Request request);
protected abstract void DoHandle(Request request);
}
// 模式二:管道式责任链 — 每个处理者都执行,可决定是否继续
// 适用场景:中间件管道(日志→认证→限流→业务)
public abstract class PipelineHandler
{
protected PipelineHandler? Next { get; private set; }
public PipelineHandler SetNext(PipelineHandler next) { Next = next; return next; }
public async Task HandleAsync(Request request)
{
var shouldContinue = await DoHandleAsync(request);
if (shouldContinue)
await (Next?.HandleAsync(request) ?? Task.CompletedTask);
}
protected abstract Task<bool> DoHandleAsync(Request request);
}
// 模式三:广播式责任链 — 所有处理者都执行(不管前一个是否处理)
// 适用场景:事件通知(所有监听者都收到事件)
public abstract class BroadcastHandler
{
protected BroadcastHandler? Next { get; private set; }
public BroadcastHandler SetNext(BroadcastHandler next) { Next = next; return next; }
public async Task HandleAsync(Request request)
{
await DoHandleAsync(request);
await (Next?.HandleAsync(request) ?? Task.CompletedTask);
}
protected abstract Task DoHandleAsync(Request request);
}性能考量与优化
// 责任链的性能开销主要来自:
// 1. 方法调用链(递归或循环)
// 2. 每个处理者的条件判断
// 3. 异步场景下的 Task 分配
// 优化策略 1:使用数组代替链表(减少指针追踪)
public class OptimizedChain<TRequest>
{
private readonly List<Func<TRequest, Task<bool>>> _handlers = new();
public void Add(Func<TRequest, Task<bool>> handler) => _handlers.Add(handler);
public async Task<bool> HandleAsync(TRequest request)
{
foreach (var handler in _handlers)
{
if (await handler(request))
return true; // 已处理,停止传递
}
return false;
}
}
// 优化策略 2:预编译条件(适用于条件固定的场景)
public class CompiledHandler<TRequest>
{
private Func<TRequest, Task<bool>>? _compiledChain;
public void AddHandler(Func<TRequest, bool> condition, Func<TRequest, Task> action)
{
var next = _compiledChain;
_compiledChain = async req =>
{
if (condition(req))
{
await action(req);
return true;
}
return next != null ? await next(req) : false;
};
}
public Task<bool> HandleAsync(TRequest request) =>
_compiledChain?.Invoke(request) ?? Task.FromResult(false);
}最佳实践
- 设置链的终止条件:确保链的末端有默认处理逻辑,避免请求无人处理。
- 控制链的长度:链过长会影响性能,建议不超过 10 个处理者。
- 处理者应该无状态:避免在处理者中保存请求相关的状态。
- 记录链路日志:在调试时记录请求经过了哪些处理者,便于排查问题。
- 考虑使用 Builder 模式:使用 Builder 模式构建链比手动 SetNext 更安全、更灵活。
优点
缺点
总结
责任链模式将请求沿处理者链传递,每个处理者决定处理或转发。ASP.NET Core 中间件管道是经典实现。审批流程按金额级别链式传递。构建时使用 SetNext 或 Builder 模式组装链。建议在请求需要多步处理、处理者动态变化的场景使用责任链模式。
责任链模式的本质价值在于:将请求的发送者和处理者解耦,让多个处理者都有机会处理请求。当你需要动态组合多个处理步骤,且发送者不需要知道具体谁会处理请求时,责任链模式是最佳选择。
关键知识点
- 模式不是目标,降低耦合和控制变化才是目标。
- 先找变化点、稳定点和协作边界,再决定是否引入模式。
- 同一个模式在不同规模下的收益和代价差异很大。
项目落地视角
- 优先画出参与对象、依赖方向和调用链,再落到代码。
- 把模式放到一个真实场景里,比如支付、规则引擎、工作流或插件扩展。
- 配合单元测试或契约测试,保证重构后的行为没有漂移。
常见误区
- 为了看起来"高级"而套模式。
- 把简单问题拆成过多抽象层,导致阅读和排障都变难。
- 只会背 UML,不会解释为什么这里需要这个模式。
进阶路线
- 继续关注模式之间的组合用法,而不是孤立记忆。
- 从业务建模、演进策略和团队协作角度看模式的适用性。
- 把模式结论沉淀为项目模板、基类或约束文档。
适用场景
- 当你准备把《责任链模式》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合在业务规则频繁变化、分支增多或对象协作复杂时引入。
- 当你希望提高扩展性,但又不想把系统拆得过度抽象时,这类主题很有参考价值。
落地建议
- 先识别变化点,再决定是否引入模式,而不是反过来套模板。
- 优先为模式的边界、依赖和调用路径画出简单结构图。
- 把模式落到一个明确场景,例如支付、规则计算、插件扩展或工作流。
排错清单
- 检查抽象层是否过多,导致调用路径和责任不清晰。
- 确认引入模式后是否真的减少了条件分支和重复代码。
- 警惕"为了模式而模式",尤其是在简单业务里。
复盘问题
- 如果把《责任链模式》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《责任链模式》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《责任链模式》最大的收益和代价分别是什么?
