一、行为型模式在面向对象的世界里如何优雅地组织对象间的交互、分配职责是每一位开发者都会反复思考的问题。直接硬编码交互逻辑固然简单但当业务复杂度上升、对象协作关系变得错综复杂时这种方式就会让代码变得僵化、难以扩展。行为型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们关注如何定义对象之间的通信方式和职责分配通过命令、迭代、观察者、策略等手段让对象间的协作更具灵活性、可复用性和可维护性。在 Java 开发中行为型模式主要包含以下 11 种经典实现模板方法模式 (Template Method)定义一个操作中的算法的骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。Java 设计模式・模板方法模式篇从思想到代码实现-CSDN博客策略模式 (Strategy)定义一系列的算法把它们一个个封装起来并且使它们可相互替换让算法独立于使用它的客户而变化。Java 设计模式・策略模式篇从思想到代码实现-CSDN博客命令模式 (Command)将一个请求封装为一个对象从而使你可以用不同的请求对客户进行参数化支持可撤销操作。Java 设计模式・命令模式篇从思想到代码实现-CSDN博客责任链模式 (Chain of Responsibility)将请求的发送者和接收者解耦使多个对象都有机会处理这个请求形成一条处理链。状态模式 (State)允许一个对象在其内部状态改变时改变它的行为对象看起来似乎修改了它的类。Java 设计模式・状态模式篇从思想到代码实现-CSDN博客观察者模式 (Observer)定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖它的对象都得到通知并被自动更新。Java 设计模式・观察者模式篇从思想到代码实现-CSDN博客中介者模式 (Mediator)用一个中介对象来封装一系列的对象交互使各对象不需要显式地相互引用从而降低耦合。Java 设计模式・中介者模式篇从思想到代码实现-CSDN博客迭代器模式 (Iterator)提供一种方法顺序访问一个聚合对象中的各个元素而又不暴露其内部的表示。访问者模式 (Visitor)表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。备忘录模式 (Memento)在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态以便以后恢复。解释器模式 (Interpreter)给定一个语言定义它的文法的一种表示并定义一个解释器这个解释器使用该表示来解释语言中的句子。二、责任链模式2.1 介绍把多个「处理者」连成一条链请求沿着链传递直到某个处理者能处理该请求为止每个处理者只负责自己的逻辑无需知道链上其他处理者的细节实现请求和处理的解耦。2.2 角色抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接。具体处理者Concrete Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。三、代码实现为了方便理解本文采用中文命名类名3.1 请求public class 请假条 { private String name; private int days; public 请假条() { } public 请假条(String name, int days) { this.name name; this.days days; } public String getName() { return name; } public void setName(String name) { this.name name; } public int getDays() { return days; } public void setDays(int days) { this.days days; } }3.2 抽象处理者角色public abstract class 审批者 { //领导上面还有领导 protected 审批者 nextHandler; public 审批者() { } //设置上级领导 public void setNextHandler(审批者 nextHandler){ this.nextHandler nextHandler; } //各级领导处理请假条方法 protected abstract void handleLeave(请假条 leave); }3.3 具体处理者角色public class 导员 extends 审批者{ public 导员() { super(); } Override protected void handleLeave(请假条 leave) { if (leave.getDays() 3){ System.out.println(导员 leave.getName() 的请假条被处理了处理结果为同意); } else { this.nextHandler.handleLeave(leave); } } }public class 院长 extends 审批者{ public 院长() { super(); } Override protected void handleLeave(请假条 leave) { if (leave.getDays() 5){ System.out.println(院长 leave.getName() 的请假条被处理了处理结果为同意); } else { this.nextHandler.handleLeave(leave); } } }public class 校长 extends 审批者{ public 校长() { super(); } Override protected void handleLeave(请假条 leave) { System.out.println(校长 leave.getName() 的请假条被处理了处理结果为同意); } }3.4 客户端public class 客户端 { public static void main(String[] args) { 请假条 leave1 new 请假条(小王, 9); 请假条 leave2 new 请假条(小张, 2); 请假条 leave3 new 请假条(小李, 4); 审批者 counselor new 导员(); 审批者 dean new 院长(); 审批者 principal new 校长(); counselor.setNextHandler(dean); dean.setNextHandler(principal); counselor.handleLeave(leave1); counselor.handleLeave(leave2); counselor.handleLeave(leave3); } }校长小王的请假条被处理了处理结果为同意 导员小张的请假条被处理了处理结果为同意 院长小李的请假条被处理了处理结果为同意 Process finished with exit code 0四、优缺点4.1 优点请求与处理解耦客户端只需要将请求提交到责任链的起点无需关心具体由哪个处理者完成处理也无需知道链的内部结构。这降低了模块间的依赖使代码更易于维护。职责单一结构清晰每个具体处理者Handler只负责自己能处理的那部分逻辑超出职责范围的请求会传递给下一个节点。这符合单一职责原则每个类的代码都更简洁、专注。灵活性与可扩展性强可以在运行时动态地新增、删除或调整处理者在链中的顺序而无需修改客户端或其他处理者的代码。这使得系统能够快速响应业务变化例如新增一个审批级别。符合开闭原则新增一个具体处理者时只需要实现抽象处理者接口并将其加入链中无需修改现有代码对扩展开放对修改关闭。4.2 缺点性能损耗如果责任链过长或者请求需要经过多个节点才能被处理会产生多次方法调用和对象传递导致系统性能下降尤其在高并发场景下更为明显。调试与排查困难请求在链中传递的路径不固定当出现问题时难以追踪请求的完整处理流程增加了调试和定位问题的难度。请求可能无法被处理如果责任链的末端没有兜底的处理者或者所有处理者都无法处理该请求会导致请求丢失需要额外的代码来处理这种异常情况。可能导致循环调用如果责任链的构建和维护不当处理者之间的引用关系出现循环会导致请求在链中无限循环造成系统崩溃。五、使用场景5.1 适合多级审批 / 流程流转如请假、报销、合同审批等每一级处理者负责特定范围的请求超出范围则转交上级。典型导员 → 院长 → 校长的请假审批流程。请求预处理链路如 Web 过滤器Servlet Filter、网关拦截器、日志记录、权限校验等。典型Spring MVC 的拦截器链依次进行身份验证、日志记录、参数校验。分级处理 / 多条件分支如日志框架中不同级别日志ERROR/INFO/DEBUG的不同输出策略。典型Log4j 中ERROR 日志发送邮件INFO 日志写入文件DEBUG 日志输出到控制台。需要动态调整处理顺序当业务规则变化频繁需要灵活增删处理节点或调整顺序时。典型风控系统中根据不同业务场景动态组合风控规则。5.2 不适合处理逻辑固定且简单如果请求的处理路径是唯一且固定的使用责任链会增加不必要的复杂度不如直接调用。反例一个简单的表单校验只有固定的 3 个校验步骤顺序不可变。对性能要求极高的场景责任链会产生多次方法调用和对象传递在高并发或低延迟要求的系统中过长的链路会成为性能瓶颈。反例高频交易系统的核心下单逻辑。需要明确知道处理结果来源如果业务要求必须明确知道请求是被哪个处理者处理的责任链的 “黑盒” 特性会增加排查难度。反例审计系统需要精确记录每一步操作的执行者。请求处理必须保证 100% 被处理如果业务不允许出现 “请求无人处理” 的情况责任链需要额外的兜底逻辑否则会增加系统风险。反例支付系统的退款请求必须确保每一笔退款都被处理。六、对比学习6.1 策略模式对比学习Java 设计模式・策略模式篇从思想到代码实现-CSDN博客对比项责任链模式 Chain of Responsibility策略模式 Strategy核心思想一个请求沿着链传递谁能处理谁处理一个行为直接选一个算法 / 策略执行处理者数量多个依次尝试一个直接选中执行流程可能中途终止不一定走完所有节点只执行选中的那一个动态性可增删节点、改顺序可切换策略但不 “传递”典型场景审批、过滤器、拦截器支付方式、排序算法、优惠计算关键区别请求找处理者链式传递客户端选策略直接调用6.2 命令模式对比学习Java 设计模式・命令模式篇从思想到代码实现-CSDN博客对比项责任链模式命令模式 Command核心思想请求沿链传递找能处理的对象请求封装成命令对象指定执行者请求与执行者解耦但不知道谁最终处理解耦但一一绑定执行次数一次请求最多一个处理者处理一个命令一个执行者特点链式传递、可终止可排队、可撤销、可记录日志典型场景审批、filter按钮点击、事务、undo/redo关键区别谁能处理谁处理谁命令谁执行6.3 装饰器模式对比学习Java 设计模式・装饰器模式篇从思想到代码实现-CSDN博客对比项责任链模式装饰器模式 Decorator核心思想请求传递处理可中途结束层层增强功能必须全部走完执行流程可能中途断掉一定会执行所有层目的分配职责让合适的对象处理增强功能不改变原对象接口结构一条链每个节点判断是否处理一层包一层每层都增强典型场景审批、权限校验IO 流、增强请求 / 响应关键区别可中途停止必须全部执行七、源码举例 Spring Interceptor7.1 角色对应责任链模式角色Spring Interceptor 对应实现抽象处理者Handlerorg.springframework.web.servlet.HandlerInterceptor接口核心方法preHandle()/postHandle()具体处理者ConcreteHandler自定义 Interceptor如TokenInterceptor、LogInterceptor责任链ChainHandlerExecutionChain维护 Interceptor 列表控制调用顺序请求对象RequestHttpServletRequest7.2 抽象处理者public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Nullable Exception ex) throws Exception { } }7.3 具体处理者RequiredArgsConstructor public class LoginInterceptor implements HandlerInterceptor { private final JwtTool jwtTool; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.获取请求头中的 token String token request.getHeader(authorization); // 2.校验token Long userId jwtTool.parseToken(token); // 3.存入上下文 UserContext.setUser(userId); // 4.放行 return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 清理用户 UserContext.removeUser(); } }7.4 责任链public class HandlerExecutionChain { ... private final ListHandlerInterceptor interceptorList; ... boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for(int i 0; i this.interceptorList.size(); this.interceptorIndex i) { HandlerInterceptor interceptor (HandlerInterceptor)this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { this.triggerAfterCompletion(request, response, (Exception)null); return false; } } return true; } ... }7.5 其他Servlet Filter过滤器链核心属于 Servlet 规范比 Spring MVC 拦截器更底层能拦截所有进入 Web 容器的请求包括静态资源、非 MVC 请求也用到了责任链模式而Spring Security中用到了过滤器链感兴趣的可以看我的一下几篇博客若依框架 SpringSecurity 基础配置源码全拆解附图解-CSDN博客若依框架 SpringSecurity 用户登录源码全拆解附图解-CSDN博客若依框架 SpringSecurity 动态菜单源码全拆解附图解-CSDN博客若依框架 SpringSecurity 数据权限源码全拆解附图解_若依框架权限-CSDN博客八、其他相关设计模式Java 设计模式・总结目录篇从思想到代码实现-CSDN博客
Java 设计模式・责任链模式篇:从思想到代码实现
一、行为型模式在面向对象的世界里如何优雅地组织对象间的交互、分配职责是每一位开发者都会反复思考的问题。直接硬编码交互逻辑固然简单但当业务复杂度上升、对象协作关系变得错综复杂时这种方式就会让代码变得僵化、难以扩展。行为型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们关注如何定义对象之间的通信方式和职责分配通过命令、迭代、观察者、策略等手段让对象间的协作更具灵活性、可复用性和可维护性。在 Java 开发中行为型模式主要包含以下 11 种经典实现模板方法模式 (Template Method)定义一个操作中的算法的骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。Java 设计模式・模板方法模式篇从思想到代码实现-CSDN博客策略模式 (Strategy)定义一系列的算法把它们一个个封装起来并且使它们可相互替换让算法独立于使用它的客户而变化。Java 设计模式・策略模式篇从思想到代码实现-CSDN博客命令模式 (Command)将一个请求封装为一个对象从而使你可以用不同的请求对客户进行参数化支持可撤销操作。Java 设计模式・命令模式篇从思想到代码实现-CSDN博客责任链模式 (Chain of Responsibility)将请求的发送者和接收者解耦使多个对象都有机会处理这个请求形成一条处理链。状态模式 (State)允许一个对象在其内部状态改变时改变它的行为对象看起来似乎修改了它的类。Java 设计模式・状态模式篇从思想到代码实现-CSDN博客观察者模式 (Observer)定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖它的对象都得到通知并被自动更新。Java 设计模式・观察者模式篇从思想到代码实现-CSDN博客中介者模式 (Mediator)用一个中介对象来封装一系列的对象交互使各对象不需要显式地相互引用从而降低耦合。Java 设计模式・中介者模式篇从思想到代码实现-CSDN博客迭代器模式 (Iterator)提供一种方法顺序访问一个聚合对象中的各个元素而又不暴露其内部的表示。访问者模式 (Visitor)表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。备忘录模式 (Memento)在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态以便以后恢复。解释器模式 (Interpreter)给定一个语言定义它的文法的一种表示并定义一个解释器这个解释器使用该表示来解释语言中的句子。二、责任链模式2.1 介绍把多个「处理者」连成一条链请求沿着链传递直到某个处理者能处理该请求为止每个处理者只负责自己的逻辑无需知道链上其他处理者的细节实现请求和处理的解耦。2.2 角色抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接。具体处理者Concrete Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。三、代码实现为了方便理解本文采用中文命名类名3.1 请求public class 请假条 { private String name; private int days; public 请假条() { } public 请假条(String name, int days) { this.name name; this.days days; } public String getName() { return name; } public void setName(String name) { this.name name; } public int getDays() { return days; } public void setDays(int days) { this.days days; } }3.2 抽象处理者角色public abstract class 审批者 { //领导上面还有领导 protected 审批者 nextHandler; public 审批者() { } //设置上级领导 public void setNextHandler(审批者 nextHandler){ this.nextHandler nextHandler; } //各级领导处理请假条方法 protected abstract void handleLeave(请假条 leave); }3.3 具体处理者角色public class 导员 extends 审批者{ public 导员() { super(); } Override protected void handleLeave(请假条 leave) { if (leave.getDays() 3){ System.out.println(导员 leave.getName() 的请假条被处理了处理结果为同意); } else { this.nextHandler.handleLeave(leave); } } }public class 院长 extends 审批者{ public 院长() { super(); } Override protected void handleLeave(请假条 leave) { if (leave.getDays() 5){ System.out.println(院长 leave.getName() 的请假条被处理了处理结果为同意); } else { this.nextHandler.handleLeave(leave); } } }public class 校长 extends 审批者{ public 校长() { super(); } Override protected void handleLeave(请假条 leave) { System.out.println(校长 leave.getName() 的请假条被处理了处理结果为同意); } }3.4 客户端public class 客户端 { public static void main(String[] args) { 请假条 leave1 new 请假条(小王, 9); 请假条 leave2 new 请假条(小张, 2); 请假条 leave3 new 请假条(小李, 4); 审批者 counselor new 导员(); 审批者 dean new 院长(); 审批者 principal new 校长(); counselor.setNextHandler(dean); dean.setNextHandler(principal); counselor.handleLeave(leave1); counselor.handleLeave(leave2); counselor.handleLeave(leave3); } }校长小王的请假条被处理了处理结果为同意 导员小张的请假条被处理了处理结果为同意 院长小李的请假条被处理了处理结果为同意 Process finished with exit code 0四、优缺点4.1 优点请求与处理解耦客户端只需要将请求提交到责任链的起点无需关心具体由哪个处理者完成处理也无需知道链的内部结构。这降低了模块间的依赖使代码更易于维护。职责单一结构清晰每个具体处理者Handler只负责自己能处理的那部分逻辑超出职责范围的请求会传递给下一个节点。这符合单一职责原则每个类的代码都更简洁、专注。灵活性与可扩展性强可以在运行时动态地新增、删除或调整处理者在链中的顺序而无需修改客户端或其他处理者的代码。这使得系统能够快速响应业务变化例如新增一个审批级别。符合开闭原则新增一个具体处理者时只需要实现抽象处理者接口并将其加入链中无需修改现有代码对扩展开放对修改关闭。4.2 缺点性能损耗如果责任链过长或者请求需要经过多个节点才能被处理会产生多次方法调用和对象传递导致系统性能下降尤其在高并发场景下更为明显。调试与排查困难请求在链中传递的路径不固定当出现问题时难以追踪请求的完整处理流程增加了调试和定位问题的难度。请求可能无法被处理如果责任链的末端没有兜底的处理者或者所有处理者都无法处理该请求会导致请求丢失需要额外的代码来处理这种异常情况。可能导致循环调用如果责任链的构建和维护不当处理者之间的引用关系出现循环会导致请求在链中无限循环造成系统崩溃。五、使用场景5.1 适合多级审批 / 流程流转如请假、报销、合同审批等每一级处理者负责特定范围的请求超出范围则转交上级。典型导员 → 院长 → 校长的请假审批流程。请求预处理链路如 Web 过滤器Servlet Filter、网关拦截器、日志记录、权限校验等。典型Spring MVC 的拦截器链依次进行身份验证、日志记录、参数校验。分级处理 / 多条件分支如日志框架中不同级别日志ERROR/INFO/DEBUG的不同输出策略。典型Log4j 中ERROR 日志发送邮件INFO 日志写入文件DEBUG 日志输出到控制台。需要动态调整处理顺序当业务规则变化频繁需要灵活增删处理节点或调整顺序时。典型风控系统中根据不同业务场景动态组合风控规则。5.2 不适合处理逻辑固定且简单如果请求的处理路径是唯一且固定的使用责任链会增加不必要的复杂度不如直接调用。反例一个简单的表单校验只有固定的 3 个校验步骤顺序不可变。对性能要求极高的场景责任链会产生多次方法调用和对象传递在高并发或低延迟要求的系统中过长的链路会成为性能瓶颈。反例高频交易系统的核心下单逻辑。需要明确知道处理结果来源如果业务要求必须明确知道请求是被哪个处理者处理的责任链的 “黑盒” 特性会增加排查难度。反例审计系统需要精确记录每一步操作的执行者。请求处理必须保证 100% 被处理如果业务不允许出现 “请求无人处理” 的情况责任链需要额外的兜底逻辑否则会增加系统风险。反例支付系统的退款请求必须确保每一笔退款都被处理。六、对比学习6.1 策略模式对比学习Java 设计模式・策略模式篇从思想到代码实现-CSDN博客对比项责任链模式 Chain of Responsibility策略模式 Strategy核心思想一个请求沿着链传递谁能处理谁处理一个行为直接选一个算法 / 策略执行处理者数量多个依次尝试一个直接选中执行流程可能中途终止不一定走完所有节点只执行选中的那一个动态性可增删节点、改顺序可切换策略但不 “传递”典型场景审批、过滤器、拦截器支付方式、排序算法、优惠计算关键区别请求找处理者链式传递客户端选策略直接调用6.2 命令模式对比学习Java 设计模式・命令模式篇从思想到代码实现-CSDN博客对比项责任链模式命令模式 Command核心思想请求沿链传递找能处理的对象请求封装成命令对象指定执行者请求与执行者解耦但不知道谁最终处理解耦但一一绑定执行次数一次请求最多一个处理者处理一个命令一个执行者特点链式传递、可终止可排队、可撤销、可记录日志典型场景审批、filter按钮点击、事务、undo/redo关键区别谁能处理谁处理谁命令谁执行6.3 装饰器模式对比学习Java 设计模式・装饰器模式篇从思想到代码实现-CSDN博客对比项责任链模式装饰器模式 Decorator核心思想请求传递处理可中途结束层层增强功能必须全部走完执行流程可能中途断掉一定会执行所有层目的分配职责让合适的对象处理增强功能不改变原对象接口结构一条链每个节点判断是否处理一层包一层每层都增强典型场景审批、权限校验IO 流、增强请求 / 响应关键区别可中途停止必须全部执行七、源码举例 Spring Interceptor7.1 角色对应责任链模式角色Spring Interceptor 对应实现抽象处理者Handlerorg.springframework.web.servlet.HandlerInterceptor接口核心方法preHandle()/postHandle()具体处理者ConcreteHandler自定义 Interceptor如TokenInterceptor、LogInterceptor责任链ChainHandlerExecutionChain维护 Interceptor 列表控制调用顺序请求对象RequestHttpServletRequest7.2 抽象处理者public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Nullable Exception ex) throws Exception { } }7.3 具体处理者RequiredArgsConstructor public class LoginInterceptor implements HandlerInterceptor { private final JwtTool jwtTool; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.获取请求头中的 token String token request.getHeader(authorization); // 2.校验token Long userId jwtTool.parseToken(token); // 3.存入上下文 UserContext.setUser(userId); // 4.放行 return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 清理用户 UserContext.removeUser(); } }7.4 责任链public class HandlerExecutionChain { ... private final ListHandlerInterceptor interceptorList; ... boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for(int i 0; i this.interceptorList.size(); this.interceptorIndex i) { HandlerInterceptor interceptor (HandlerInterceptor)this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { this.triggerAfterCompletion(request, response, (Exception)null); return false; } } return true; } ... }7.5 其他Servlet Filter过滤器链核心属于 Servlet 规范比 Spring MVC 拦截器更底层能拦截所有进入 Web 容器的请求包括静态资源、非 MVC 请求也用到了责任链模式而Spring Security中用到了过滤器链感兴趣的可以看我的一下几篇博客若依框架 SpringSecurity 基础配置源码全拆解附图解-CSDN博客若依框架 SpringSecurity 用户登录源码全拆解附图解-CSDN博客若依框架 SpringSecurity 动态菜单源码全拆解附图解-CSDN博客若依框架 SpringSecurity 数据权限源码全拆解附图解_若依框架权限-CSDN博客八、其他相关设计模式Java 设计模式・总结目录篇从思想到代码实现-CSDN博客