责任链模式

点击阅读:设计模式系列文章


1. 责任链模式的定义

责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,它的核心思想是: 将请求的发送者与处理者解耦,使多个对象都有机会处理请求,并将请求沿链传递,直到被处理。

  1. 解耦请求发送者与处理,发送者不知道谁最终处理请求。
  2. 支持动态组合和顺序变更。
  3. 链上的节点可以自由决定是否处理请求。每个处理者可以决定:自己处理或传给下一个。

两类模型:

  1. 短路型 (Short-circuit) :链上任何一个节点处理完请求后,直接中断,不再向下传递。适用于"权限校验"、"参数验证"等场景,一旦发现问题就无需继续。
  2. 贯穿型 (Pass-through) :链上所有节点都会处理请求,每个节点处理完后都会传递给下一个。适用于"日志记录"、"性能监控"、"数据审计"等需要多重处理的场景。

2. 责任链模式的结构

责任链模式主要包含以下角色:

  • Handler(抽象处理者): 定义处理请求的接口,并持有对下一个处理者的引用。
  • ConcreteHandler(具体处理者):实现抽象处理者接口,决定是否处理请求或将请求传递。
  • Client(客户端):发送请求,不关心具体由谁处理。
txt 复制代码
Client
   |
Handler (抽象)
   |
ConcreteHandler1 --> ConcreteHandler2 --> ConcreteHandler3 ...

特点

  • 链可以是单向的,也可以是动态构建的。
  • 节点顺序决定请求处理的优先级。
  • 可以使用递归或循环遍历链。

2.1 Handler 抽象处理者

java 复制代码
public abstract class Handler {
    protected Handler next;

    public Handler setNext(Handler next) {
        this.next = next;
        return next;
    }

    public final void handle(RequestContext ctx) {
        if (onHandle(ctx)) {
            return;
        }
        if (next != null) {
            next.handle(ctx);
        }
    }

    protected abstract boolean onHandle(RequestContext ctx);
}

2.2 ConcreteHandler 具体处理者

java 复制代码
public class AuthHandler extends Handler {
    @Override
    protected boolean onHandle(RequestContext ctx) {
        String token = (String) ctx.get("token");
        if (token == null || token.isEmpty()) {
            throw new RuntimeException("unauthorized");
        }
        return false;
    }
}

public class ParamValidateHandler extends Handler {
    @Override
    protected boolean onHandle(RequestContext ctx) {
        Object uid = ctx.get("userId");
        if (uid == null) {
            throw new IllegalArgumentException("userId required");
        }
        return false;
    }
}

public class BizHandler extends Handler {
    @Override
    protected boolean onHandle(RequestContext ctx) {
        System.out.println("do real business");
        return true;
    }
}

2.3 Client 客户端

java 复制代码
// 客户端调用
public class Client {
    public static void main(String[] args) {
        RequestContext ctx = new RequestContext();
        ctx.put("token", "abc");
        ctx.put("userId", 123);

        Handler head = new AuthHandler();
        head.setNext(new ParamValidateHandler())
            .setNext(new BizHandler());

        head.handle(ctx);
    }
}

public class RequestContext {
    private final Map<String, Object> attrs = new HashMap<>();

    public void put(String key, Object value) {
        attrs.put(key, value);
    }

    public Object get(String key) {
        return attrs.get(key);
    }
}

3. 责任链模式的优缺点

优点 :

  1. 降低耦合:发送者不关心谁处理请求。
  2. 增强灵活性:链可动态增加、删除节点。
  3. 符合开闭原则:新增节点无需修改现有代码。
  4. 职责单一:每个节点只负责自身处理逻辑。

缺点 :

  1. 链过长可能影响性能
  2. 请求可能无人处理,需要合理设计默认处理策略。
  3. 调试难度:链式调用和递归可能难以追踪。
  4. 节点顺序敏感:链条顺序不当可能导致逻辑错误。

4. 责任链模式的设计思想

  • 解耦请求发送者与处理者

  • 单一职责:节点只处理自身逻辑。

  • 递归/循环链式传递,体现动态和灵活。

  • 开闭原则:新增节点无需改动原有链。

  • 可扩展性:适合多种复杂业务场景。

5. 一些问题

Q1: 责任链模式与装饰器模式的区别是什么?

A1:

  • 责任链模式:多个处理器按顺序尝试处理同一个请求,直到有一个处理器能够处理为止(或全部处理完)
  • 装饰器模式:对同一个对象进行层层包装,每层都增加新的功能
  • 核心区别:责任链强调"选择性处理",装饰器强调"功能叠加"
java 复制代码
// 责任链:只有一个处理器会处理请求
handler1.handle(request) -> handler2.handle(request) -> handler3.handle(request)

// 装饰器:每层都会处理,功能叠加
decorator1(decorator2(decorator3(core)))

Q2: 责任链模式在什么场景下不适用?

  1. 处理逻辑简单且固定

    • 解释:如果处理步骤始终固定且不需要动态调整,那么直接用顺序调用或 if-else 就足够。
    • 例子:一个请求只需要固定地经过 A→B→C 三个处理器,且不会变更。此时用责任链反而显得多余、复杂。
  2. 性能要求极高

    • 解释:责任链需要依次遍历处理器,每次调用都涉及方法分发甚至对象查找,存在额外开销。
    • 例子:在 Android Framework 的核心渲染或输入事件分发等高频调用场景,如果链很长,会产生明显性能损耗。
  3. 处理器之间有强依赖关系

    • 解释 :责任链强调 解耦(各处理器独立,不关心前后顺序细节)。但如果处理器必须依赖上一步的具体实现,责任链就不合适。
    • 例子:步骤 B 必须依赖步骤 A 的内部状态或返回值,而不仅仅是一个统一的上下文参数,这种强依赖违背了解耦设计。
  4. 需要回滚操作

    • 解释:责任链是单向流转,请求被传递下去后通常不追溯处理历史。如果业务需要类似事务的回滚(所有步骤要么全部成功,要么全部撤销),责任链难以实现。
    • 例子:在数据库批处理或支付流程中,某个处理失败时需要撤销之前已完成的步骤;责任链无法天然支持,需要额外补偿机制。
相关推荐
itseeker7 小时前
只需 5 分钟,让你的 Android App 快速接入 MCP 协议,打通 LLM 的调度
android·github
用户207038619497 小时前
Android AutoService 解耦实战
android
顾林海7 小时前
OkHttp拦截器:Android网络请求的「瑞士军刀」
android·面试·性能优化
现在没有牛仔了7 小时前
用Spring Boot+工厂+策略模式优雅解耦支付系统
java·后端·设计模式
就是帅我不改7 小时前
震惊!高并发下,我竟用Spring普通Bean实现了线程级隔离!
后端·面试·github
jctech7 小时前
解构ComboLite:0 Hook的背后,是哪些精妙的架构设计?
android
jctech7 小时前
从0到1,用`ComboLite`构建一个“万物皆可插拔”的动态化App
android
jctech7 小时前
你的App越来越“胖”了吗?给Android应用“减肥”的终极秘诀——插件化
android
Alporal7 小时前
前端小白误闯天家:项目选什么?该不该往新技术方向包装
面试