责任链模式在C#中需手动串联Handler对象,关键在于每个处理者对请求的判断逻辑和转发时机;应优先使用抽象基类实现默认SetNext和Handle转发逻辑,避免空引用与静默丢失,并确保链尾有兜底处理器。

责任链模式在 C# 里不是靠框架自动装配的,而是靠你手动串起一串 Handler 对象,并控制请求是否继续往下传——关键不在“链”本身,而在每个处理者对 request 的判断逻辑和转发时机。
怎么定义 Handler 接口或基类
别直接写抽象类再继承,先想清楚要不要支持链式调用、要不要统一默认转发逻辑。用接口 + 抽象基类组合最稳妥:
-
IHandler只定义SetNext(IHandler)和Handle(Request),不带状态 -
AbstractHandler实现公共字段_nextHandler和默认转发行为:_nextHandler?.Handle(request) - 具体处理器只重写
Handle,内部用if判断是否自己处理;不满足条件时显式调用base.Handle(request),而不是无脑 return
漏掉 base.Handle(request) 是新手最常踩的坑:看起来写了“else 继续传”,结果什么都没做,请求就丢了。
SetNext 怎么支持链式调用
SetNext 方法必须返回 IHandler(通常是 this 或传入的 handler),否则写不出 h1.SetNext(h2).SetNext(h3) 这种链式写法。
- 返回
this:适合构建者模式风格,比如new HandlerA().SetNext(new HandlerB()) - 返回
handler:更常见,方便连续设置下游,如示例中handlerA.SetNext(handlerB).SetNext(defaultHandler) - 注意不要在
SetNext里做权限比较或自动插入排序——那是业务逻辑,不是责任链基础设施该干的事
如何避免请求中途静默丢失
没有被任何 Handler 处理的请求,最终必须有个兜底。否则调试时你会看到:发了请求,没输出,也没异常,就像被吞了一样。
- 链尾一定要接一个
DefaultHandler或类似实现,Handle方法至少打日志或抛异常 - 不要依赖“最后一个 handler 不处理就自动结束”——C# 不会自动帮你 catch 未处理场景
- 如果用泛型请求类型(如
Request<t></t>),确保每个Handler的类型检查逻辑覆盖全,别因类型擦除漏判
什么时候不该用责任链
责任链容易让人误以为“加个新 Handler 就完事”,但实际中几个硬伤很致命:
- 所有
Handler必须共享同一套Request结构,字段增减要同步改全部处理器 - 无法回溯:A 处理完传给 B,B 处理失败,你没法让 A 补救——它早已退出调用栈
- 性能敏感路径慎用:每层都要虚方法调用 + 条件判断,比直接 if-else 分支略重
- Unity 里频繁创建
Handler实例(尤其 MonoBehaviour 派生)可能触发 GC,建议对象池复用
真正该用的时候,是那些“流程固定、参与者可插拔、失败不需回滚”的场景,比如日志分级分发、审批流、输入事件预处理——而不是所有“要分步骤”的地方都套一层链。


















