责任链模式:代码世界里的击鼓传花

沐风 2026-3-2--最后更新: 2026-5-28
type
status
date
slug
summary
tags
category
icon
password
wechat_gate

责任链模式:代码世界里的击鼓传花

假如你在做一个 OA 系统的请假审批功能。
需求文档摆在桌上,写得清清楚楚:请假不超过 3 天,主任审;3 到 10 天,经理审;10 到 30 天,总经理审;超过 30 天,一律拒绝。
刚开始写代码的时候,我们会毫不犹豫地打开if-else
写完一看,逻辑没毛病。
但产品经理走过来说:「以后可能要加副总裁审批,超过 30 天的让他来处理。」
想必我们的表情会当场垮了。

问题出在哪里

表面上代码能跑,本质上耦合死了
审批逻辑全集中在一个方法里,每加一个层级,就要改这段代码。每次改动,都可能引入新的 bug。更糟的是:负责审批的人(Director、Manager、GeneralManager)根本不知道彼此的存在,却被一个外部方法强行调度。
这违反了一个基本原则:每个处理者应该只知道"我能不能处理",以及"处理不了就交给谁"。
这,就是责任链模式要解决的问题。

责任链模式是什么

GoF 给出的定义很简洁:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
翻译成人话:把处理者串成一条链,请求从头开始一个个往后传,谁能处理谁接手,处理不了就继续传。
类图长这样:
每个 ConcreteHandler 持有一个 successor 指针,指向链上的下一个处理者。这个结构有点像链表——每个节点只认识自己的下一个,不需要了解整条链。

用责任链重写假条审批

先定义抽象处理者,它只做两件事:持有后继者、声明处理方法。
三个具体处理者,每个只关心自己的审批权限:
组装责任链:
现在,产品经理来说要加副总裁了——完全不慌。
开闭原则:对扩展开放,对修改关闭。这才是正确的姿势。

责任链不是万能的

有个问题是:责任链"不可以"做到的事是什么?
答案是:高效率地处理请求。
责任链本质上是顺序遍历。最坏情况下,一个请求要走完整条链才能找到处理者,或者根本无人处理。它换来的是灵活性和解耦,代价是效率。
如果你有一个需求,要求精准匹配、直接命中处理者,那应该用策略模式或者简单的 Map 路由,而不是责任链。
用模式,要知道它的边界。

工作中它长什么样

责任链在框架层面其实无处不在,只是换了个名字:
Spring Security 的过滤器链
每个 Filter 都可以选择:处理后继续传、处理后中断、直接拦截返回。这是工业级的责任链实现。
Servlet Filter
FilterChain 就是那根链,chain.doFilter() 就是在说:我处理完了,传给下一个吧。
Netty 的 ChannelPipeline 也是同样的设计,所有入站出站事件都沿 pipeline 流动。

识别责任链的信号

读需求文档的时候,如果你看到这些描述,几乎可以断定是责任链的场景:
  • "按级别处理":权限不够就往上报
  • "依次判断":一个个条件往下过
  • "不归我管就转交":处理者之间有传递关系
  • "审批流、过滤器、拦截器":这三个词出现,基本就是它了

最后说一句

古代官府有个制度叫「层层上报」——小事县令决,大事知府定,军国大事上达天听。每一级官员只需知道:这件事我能不能拍板,不能就往上递。
千年前的行政智慧,被我们封装进了一个设计模式。
代码的世界里,好的设计从来不是凭空发明的。它们藏在历史的褶皱里,等着被重新发现。

 
2026.03.02 12:06 沪 · 赵巷