责任链模式

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


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. 需要回滚操作

    • 解释:责任链是单向流转,请求被传递下去后通常不追溯处理历史。如果业务需要类似事务的回滚(所有步骤要么全部成功,要么全部撤销),责任链难以实现。
    • 例子:在数据库批处理或支付流程中,某个处理失败时需要撤销之前已完成的步骤;责任链无法天然支持,需要额外补偿机制。
相关推荐
zh_xuan27 分钟前
Android 传统view嵌入compose
android
ZHANG13HAO3 小时前
Android 13 AOSP 内置 NekoTTS 中文免费商用 TTS 完整流程
android
许杰小刀7 小时前
ctfshow-web文件包含(web78-web86)
android·前端·android studio
java1234_小锋8 小时前
Java高频面试题:Springboot的自动配置原理?
java·spring boot·面试
xiaoye37089 小时前
Spring 中高级面试题
spring·面试
前端大波11 小时前
前端面试通关包(2026版,完整版)
前端·面试·职场和发展
恋猫de小郭12 小时前
Android 上为什么主题字体对 Flutter 不生效,对 Compose 生效?Flutter 中文字体问题修复
android·前端·flutter
三少爷的鞋12 小时前
不要让调用方承担你本该承担的复杂度 —— Android Data 层设计原则
android
李李李勃谦12 小时前
Flutter 框架跨平台鸿蒙开发 - 创意灵感收集
android·flutter·harmonyos