← 返回题目列表

纯责任链和不纯责任链有什么区别?

高频 中等 第 3 / 27 题 更新于 2026/07/28
责任链模式纯责任链不纯责任链短路设计模式

简化版

纯责任链要求一个请求最终只能被一个处理器处理,处理后链路结束;不纯责任链允许多个处理器共同处理同一个请求,也允许某些节点只做增强后继续传递。真实项目里更常见的是不纯责任链,比如过滤器链、拦截器链和网关链路。

详细版

纯责任链更接近经典定义:请求沿链传递,直到某个处理器能处理它,处理完成后不再向后传递。如果链上没有处理器能处理,可能走默认逻辑或返回失败。

不纯责任链更接近工程实践:一个请求可能被多个处理器依次处理。比如一次 HTTP 请求进入系统后,日志、鉴权、限流、参数校验、业务处理都可能执行,每个节点都承担一部分职责。

区别可以从三点看:

  1. 处理者数量:纯责任链通常一个处理者处理;不纯责任链可能多个处理者处理;
  2. 传递方式:纯责任链命中后停止;不纯责任链处理后可能继续;
  3. 使用场景:纯责任链适合审批、路由分发;不纯责任链适合过滤器、校验链、增强链。

面试时可以补充:设计模式不是死模板,真实框架中大量责任链都是不纯责任链,但仍然符合“请求沿处理器链传递、发送者与处理者解耦”的核心思想。

完整版教学

一、纯责任链强调“谁能处理就交给谁”

纯责任链的典型语义是:一个请求只需要一个处理者完成。

比如请假审批:

  • 1 天以内主管审批;
  • 3 天以内经理审批;
  • 7 天以内总监审批。

伪代码可以这样写:

class ManagerHandler extends Handler {
    void handle(LeaveRequest request) {
        if (request.getDays() <= 3) {
            approve(request);
            return;
        }
        next.handle(request);
    }
}

一旦经理能处理,就不会再交给总监。

这种链路像“找负责人”:请求不是让每个人都处理,而是沿着链寻找合适的人。

二、不纯责任链强调“多个节点分段处理”

不纯责任链中,多个处理器都可能处理同一个请求。

比如 Web 请求:

请求 -> 日志过滤器 -> 鉴权过滤器 -> 限流过滤器 -> 业务处理器 -> 响应

日志过滤器不会说“我记录完日志,所以业务不用执行了”。它通常会处理一部分逻辑,然后继续放行。

示意代码:

class LogFilter implements Filter {
    void doFilter(Request request, FilterChain chain) {
        long start = System.currentTimeMillis();
        chain.doFilter(request);
        long cost = System.currentTimeMillis() - start;
        log.info("cost={}", cost);
    }
}

这里日志过滤器既处理了请求,又让请求继续向后传递。

三、两者的核心差异在“处理后是否继续”

纯责任链:

A 不能处理 -> B 不能处理 -> C 能处理 -> 停止

不纯责任链:

A 处理并继续 -> B 处理并继续 -> C 处理并继续 -> 结束

当然,不纯责任链也可以短路。比如鉴权失败后直接返回 401,不再进入后面的限流和业务处理器。

因此不纯责任链更灵活:它既支持增强,也支持拦截。

四、为什么真实项目更常见不纯责任链

真实系统中,一个请求往往不是由某一个节点单独完成,而是需要多个横切能力协同:

  • 日志记录;
  • 身份认证;
  • 权限判断;
  • 限流;
  • 参数校验;
  • 灰度规则;
  • 业务执行;
  • 响应包装。

这些能力天然适合拆成多个节点逐步处理,所以不纯责任链在 Web 框架、RPC 框架、网关、消息消费、风控系统里特别常见。

五、纯责任链更适合“路由型处理”

纯责任链更适合下面这些问题:

  • 谁来审批;
  • 谁来解析这种格式;
  • 谁来处理这种命令;
  • 谁来兜底这种异常;
  • 哪个路由规则命中请求。

这些问题的特征是:请求最终通常只需要一个处理者。

如果多个处理器都执行,反而可能重复处理或造成副作用。

六、答题时不要把“不纯”理解成“不规范”

“不纯责任链”里的“不纯”不是贬义。它只是说它不完全符合经典定义中“只由一个处理者处理”的限制。

很多成熟框架都使用不纯责任链思想。比如过滤器链、拦截器链、插件链,本质上都允许多个节点处理同一请求。

面试时可以这样表达:经典责任链偏请求分派,工程责任链偏流程增强,两者都围绕链式传递和解耦处理者展开。

七、命中一个与逐段处理的差异

纯链 5 个处理器中通常只有 1 个最终处理;不纯链可能让 5 个节点全部增强同一请求,执行次数从 1 变为 5。

pure: pass... -> one handles; impure: H1 -> H2 -> H3 all may process

责任链是否正确,不能只看节点都被注册,还要看请求到底经过哪些节点、在哪里停止以及返回阶段如何展开。应把“继续、已处理、拒绝、系统失败”建成可区分的结果,并让日志能够还原一次请求的完整路径。

八、链路顺序、短路与可观测性

检查维度应确认的内容
机制正确性回答时应落到处理后是否继续、结果如何合并,而不是纠结名称。
适用边界“纯/不纯”是工程分类,不是价值判断;真实过滤器链常允许多个节点处理并继续。
测试证据对同一请求分别验证首节点命中、中间节点命中和走到链尾,断言实际执行节点集合
工程代价重点测量链长、各节点耗时、最坏路径延迟和短路率,并确认动态装配不会产生重复节点或排序漂移

易错点:回答时应落到处理后是否继续、结果如何合并,而不是纠结名称。

九、常见误区与追问

  • 误区:不纯责任链是不规范的实现。 它只是允许多个节点分段处理,Servlet Filter 等工程实践正是常见例子。
  • 误区:责任链一定会让每个处理器都执行。 纯链可能命中一个节点就结束,不纯链也可能因拒绝、异常或短路提前终止,必须由链契约定义。
  • 追问:纯链如何避免多个节点都声称能处理? 定义匹配优先级和首个命中即停止,并用测试覆盖条件重叠。
  • 追问:责任链如何避免请求到链尾无人处理? 提供明确的默认处理器或链尾失败结果,并对未处理请求记录指标,不能静默成功。
  • 追问:责任链上线后最少要记录哪些信息? 至少记录链版本、节点顺序、逐节点耗时与决策、短路位置、异常和最终处理结果。

十、加强记忆

纯责任链记成“找到一个能处理的人就停”,不纯责任链记成“多个节点可以依次处理,也可以中途拦截”。审批、路由、命令分派更偏纯责任链;过滤器、拦截器、网关、校验链更偏不纯责任链。真实项目里不纯责任链更常见。