责任链模式:让每个对象都有机会处理请求

责任链模式,说白了就是一条处理流水线。每个节点只关心自己能不能处理,处理不了就往后传。我刚开始接触这个模式时,觉得它跟if-else链没啥区别,直到在项目中遇到一个审批流程,才真正体会到它的妙处。

什么是责任链模式?

先看一个生活中的例子。你请假3天,组长批了就行。请假7天,组长批完还得经理批。请假15天,那得总监也过目。每个审批人只负责自己权限内的部分,超出范围就往上抛。这就是责任链的雏形。

在软件世界里,责任链模式的定义是:将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。这些对象串成一条链,请求沿着链传递,直到被处理为止。

核心结构

责任链模式的结构其实很简单,就三个角色:

  • Handler(抽象处理者):定义处理请求的接口,同时维护下一个处理者的引用
  • ConcreteHandler(具体处理者):实现自己的处理逻辑,决定是处理还是转发
  • Client(客户端):组装链并发送请求

我画了一张图,帮你直观理解这个结构:

责任链模式结构图 Client(客户端) Handler1(具体处理者) next Handler2(具体处理者) next Handler3(具体处理者) 处理逻辑 1. 判断能否处理 2. 能处理→执行 3. 不能→传给next 4. 链尾→默认处理 或抛异常

代码实现

光说不练假把式。咱们直接看代码,我以请假审批为例:

// 抽象处理者
public abstract class Approver {
    protected Approver nextApprover;
    protected String name;
    
    public Approver(String name) {
        this.name = name;
    }
    
    public void setNextApprover(Approver next) {
        this.nextApprover = next;
    }
    
    // 模板方法:定义处理流程
    public void handleRequest(int days) {
        if (canApprove(days)) {
            doApprove(days);
        } else if (nextApprover != null) {
            nextApprover.handleRequest(days);
        } else {
            System.out.println("无人能审批,拒绝!");
        }
    }
    
    protected abstract boolean canApprove(int days);
    protected abstract void doApprove(int days);
}

// 具体处理者:组长
public class TeamLeader extends Approver {
    public TeamLeader(String name) {
        super(name);
    }
    
    @Override
    protected boolean canApprove(int days) {
        return days <= 3;
    }
    
    @Override
    protected void doApprove(int days) {
        System.out.println(name + "(组长)审批了" + days + "天假期");
    }
}

// 具体处理者:经理
public class Manager extends Approver {
    public Manager(String name) {
        super(name);
    }
    
    @Override
    protected boolean canApprove(int days) {
        return days <= 7;
    }
    
    @Override
    protected void doApprove(int days) {
        System.out.println(name + "(经理)审批了" + days + "天假期");
    }
}

// 具体处理者:总监
public class Director extends Approver {
    public Director(String name) {
        super(name);
    }
    
    @Override
    protected boolean canApprove(int days) {
        return days <= 15;
    }
    
    @Override
    protected void doApprove(int days) {
        System.out.println(name + "(总监)审批了" + days + "天假期");
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        // 组装责任链
        Approver teamLeader = new TeamLeader("张三");
        Approver manager = new Manager("李四");
        Approver director = new Director("王五");
        
        teamLeader.setNextApprover(manager);
        manager.setNextApprover(director);
        
        // 发送请求
        teamLeader.handleRequest(2);   // 组长审批
        teamLeader.handleRequest(5);   // 经理审批
        teamLeader.handleRequest(10);  // 总监审批
        teamLeader.handleRequest(20);  // 无人能审批
    }
}
💡 我的小技巧:实际项目中,我习惯把链的组装放在配置文件中,或者用工厂方法创建。这样哪天审批规则变了,改配置文件就行,不用动代码。

优缺点分析

优点 缺点
  • 解耦发送者和接收者:客户端不知道谁处理,只负责发请求
  • 灵活性强:可以动态调整链的顺序和成员
  • 符合开闭原则:新增处理者不用改现有代码
  • 职责单一:每个处理者只关心自己的逻辑
  • 性能问题:链太长时,请求遍历会慢
  • 调试困难:请求在链中流转,出问题不好定位
  • 可能被忽略:如果链尾没有兜底处理,请求可能无人响应
  • 循环引用风险:不小心把链搞成环,就死循环了
⚠️ 避坑指南:我曾经在一个项目中,把责任链搞了十几层。结果线上有个请求卡在链里,排查了半天才发现是某个处理者忘了调用next。后来我定了个规矩:责任链不超过5层,超过就要考虑重构。

应用场景

责任链模式在哪些地方用得最多?我总结了几类:

  1. 审批流程:请假、报销、采购等需要逐级审批的业务
  2. 过滤器/拦截器:Java Servlet中的Filter链、Spring的Interceptor链
  3. 日志框架:Log4j、Logback中的Logger链,日志级别不够就往上抛
  4. 异常处理:try-catch块本身就是一种责任链,catch按顺序匹配
  5. 事件处理:GUI中的事件冒泡机制,从子组件传到父组件

你想想看,这些场景是不是都有一个共同点?处理者之间有明确的优先级或层级关系,而且每个处理者只关心自己能力范围内的事。

与if-else的区别

有人会问:用if-else也能实现类似效果,为啥非要用责任链?

嗯,这个问题问得好。我举个例子你就明白了:

// if-else方式
public void handle(int days) {
    if (days <= 3) {
        // 组长处理
    } else if (days <= 7) {
        // 经理处理
    } else if (days <= 15) {
        // 总监处理
    } else {
        // 拒绝
    }
}

这段代码有什么问题?所有处理逻辑耦合在一起。哪天要加个副总裁审批,你得改这个if-else块。哪天要调整审批顺序,你还得改。说白了,if-else是硬编码,责任链是动态组合

核心区别一句话:if-else是编译时确定的,责任链是运行时动态的。如果你的处理逻辑经常变化,或者需要灵活组合,那就用责任链。如果逻辑固定不变,if-else更简单直接。

实际项目中的变体

我在项目中见过两种责任链的变体,挺有意思:

  • 纯责任链:请求必须被某个处理者处理,否则抛异常。适合审批流程。
  • 不纯责任链:请求可以被多个处理者处理,每个处理者处理完一部分,继续往下传。适合过滤器链。

举个例子,日志框架就是典型的不纯责任链。一条日志消息,可能同时被控制台、文件、远程服务器三个处理者处理。每个处理者处理完,不阻断,继续往下传。

我个人更常用不纯责任链,因为它更灵活。但要注意,不纯责任链容易导致重复处理,需要设计好终止条件。

总结

责任链模式,说白了就是把一堆处理者串起来,让请求自己找路。它的精髓在于解耦——发送者不用关心谁处理,处理者不用关心谁来发。

记住几个要点:

  • 链的组装要灵活,最好能配置化
  • 链不要太长,5层以内为宜
  • 链尾一定要有兜底处理,避免请求丢失
  • 调试时可以在每个处理者加日志,方便追踪

好了,责任链模式就讲到这里。下一章咱们聊聊另一种行为型模式——命令模式,看看怎么把请求封装成对象。


公众号:蓝海资料掘金营,微信deep3321