责任链模式

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


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

    • 解释:责任链是单向流转,请求被传递下去后通常不追溯处理历史。如果业务需要类似事务的回滚(所有步骤要么全部成功,要么全部撤销),责任链难以实现。
    • 例子:在数据库批处理或支付流程中,某个处理失败时需要撤销之前已完成的步骤;责任链无法天然支持,需要额外补偿机制。
相关推荐
菠菠萝宝11 小时前
【Java八股文】12-分布式面试篇
java·分布式·zookeeper·面试·seata·redisson
yujkss11 小时前
23种设计模式之【原型模式】-核心原理与 Java实践
java·设计模式·原型模式
phdsky11 小时前
【设计模式】命令模式
设计模式·命令模式
青草地溪水旁11 小时前
设计模式(C++)详解——命令模式(1)
c++·设计模式·命令模式
青草地溪水旁11 小时前
设计模式(C++)详解——命令模式(2)
c++·设计模式·命令模式
用户20187928316711 小时前
轻松理解Ashmem实现原理
android
new_daimond11 小时前
设计模式-原型模式详解
设计模式·原型模式
南北是北北11 小时前
协程suspend 如何被编译成“状态机”
面试
星星点点洲12 小时前
【Golang】数据设计模式
开发语言·设计模式·golang
步行cgn12 小时前
责任链设计模式详解
设计模式