ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

责任链模式(Chain of Responsibility)实战指南:基于 java-design-patterns 仓库构建可扩展的请求处理链

责任链模式(Chain of Responsibility)实战指南:基于 java-design-patterns 仓库构建可扩展的请求处理链 示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载导读本文以 java-design-patterns 仓库中的 chain-of-responsibility 模块为核心系统讲解责任链Chain of Responsibility这一行为型设计模式它如何将请求的发送者与接收者解耦让多个处理对象依次获得处理机会直到链上某个环节接手。读完本文你将掌握责任链模式的意图、适用场景、优劣势并能结合仓库源码理解其接口设计、优先级排序机制与测试验证方式直接将其复用到日志过滤、中间件、审批流等真实业务中。模式概述责任链解决什么问题责任链模式Chain of Responsibility是 Gang of Four 提出的经典行为型设计模式别名包括Chain of Command命令链、Chain of Objects对象链、Responsibility Chain职责链。它的核心意图是解耦请求的发送者与接收者——不把请求直接绑定到某个具体处理者而是让多个对象都有机会处理请求。这些接收对象被组织成一条链请求沿着链向后传递直到某个对象将其处理完毕。正如本模块入口类 App.java 的注释所概括的责任链由一组命令对象和一系列处理对象组成每个处理对象内部包含判断自己能否处理该类命令的逻辑无法处理的命令则交给链中的下一个处理对象同时提供在链尾追加新处理对象的机制。现实世界类比技术支持呼叫中心设想一个技术支持呼叫中心每一级支持人员都是链上的一个处理节点。客户来电后请求先到达一线支持代表如果问题简单一线直接解决如果问题复杂则升级给二线技术员若仍未解决再继续向更高级别升级直到有能力的专家接手。每一级都是链上的一个 handler请求沿链逐级传递直到找到合适的处理者——发送者无需知道具体由谁处理这正是责任链模式在现实中的典型映射。一句话通俗解释责任链帮助我们构建一条对象链请求从链的一端进入在对象之间依次传递直到遇到一个合适的处理者将其接住。Wikipedia 定义在面向对象设计中责任链模式由命令对象的源头和一系列处理对象组成。每个处理对象包含定义它能处理哪些命令对象的逻辑其余命令则传递给链中的下一个处理对象。责任链的请求流转流程下图完整呈现了请求在责任链中的流转逻辑客户端发起请求从 Handler 1 开始依次判断Can Handler X process it?能处理则就地处理Handler X processes request不能处理则交给下一个处理者若整条链都没有处理者能接住则请求最终落入Request unhandled未被处理状态。从这张流程图可以提炼出责任链的两个关键设计决策每个节点都要回答我能否处理——在仓库实现中对应RequestHandler.canHandleRequest(Request)。链的终点必须考虑无人处理的兜底——这也是下文优缺点中会讨论的 catch-all handler 问题。编程示例兽人王国的命令链在 java-design-patterns 的 chain-of-responsibility 模块中责任链以一个生动的兽人王国场景演示兽人国王发出洪亮的命令最先响应的是指挥官commander然后是军官officer最后是士兵soldier三者构成一条责任链。请求对象Request 与 RequestType首先看请求载体 Request.javaGetter public class Request { private final RequestType requestType; private final String requestDescription; private boolean handled; public Request(final RequestType requestType, final String requestDescription) { this.requestType Objects.requireNonNull(requestType); this.requestDescription Objects.requireNonNull(requestDescription); } public void markHandled() { this.handled true; } Override public String toString() { return getRequestDescription(); } } public enum RequestType { DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX }从源码看Request有几个值得注意的实现细节GetterLombok自动生成getRequestType()、getRequestDescription()、isHandled()构造器对requestType与requestDescription都执行Objects.requireNonNull从源头杜绝空请求进入责任链handled字段是单向状态机只能通过markHandled()从未处理变为已处理不存在取消处理的反向操作——正如 Request.java 的注释所强调的RequestType枚举定义了三类请求DEFEND_CASTLE守城、TORTURE_PRISONER审讯囚犯、COLLECT_TAX收税每一类恰好对应链上的一个处理者。处理者接口RequestHandler责任链的抽象处理者角色是接口 RequestHandler.javapublic interface RequestHandler { boolean canHandleRequest(Request req); int getPriority(); void handle(Request req); String name(); }接口的四个方法各司其职方法作用在本示例中的实现canHandleRequest(Request)判断当前处理者能否处理该请求按RequestType匹配getPriority()返回处理优先级用于确定链上顺序士兵 1、指挥官 2、军官 3handle(Request)实际处理请求并调用markHandled()记录日志并标记已处理name()返回处理者名称用于日志输出如 Orc commander三个具体处理者OrcCommander / OrcOfficer / OrcSoldier三个具体处理者均实现RequestHandler接口代码结构完全对称。以 OrcCommander.java 为例Slf4j public class OrcCommander implements RequestHandler { Override public boolean canHandleRequest(Request req) { return req.getRequestType() RequestType.DEFEND_CASTLE; } Override public int getPriority() { return 2; } Override public void handle(Request req) { req.markHandled(); LOGGER.info({} handling request \{}\, name(), req); } Override public String name() { return Orc commander; } }OrcOfficer与OrcSoldier的定义方式完全相同差异仅在各自的处理类型与优先级上。综合三个类的源码责任链的职责分配如下表处理者源码文件能处理的请求类型优先级名称OrcSoldierOrcSoldier.javaCOLLECT_TAX1Orc soldierOrcCommanderOrcCommander.javaDEFEND_CASTLE2Orc commanderOrcOfficerOrcOfficer.javaTORTURE_PRISONER3Orc officer注意这里的优先级数字并非链的传递顺序而用于谁能优先接管请求的排序。读者可以对比传统责任链后一个 handler 持有前一个的引用、逐个next传递与本实现的差异——本示例采用每个 handler 独立判断 统一按优先级挑选的方式这是责任链模式的一种流式变体。链的构建与请求分发OrcKing兽人国王 OrcKing.java 既是命令的发起者也是责任链的构建者与分发器public class OrcKing { private ListRequestHandler handlers; public OrcKing() { buildChain(); } private void buildChain() { handlers Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier()); } public void makeRequest(Request req) { handlers .stream() .sorted(Comparator.comparing(RequestHandler::getPriority)) .filter(handler - handler.canHandleRequest(req)) .findFirst() .ifPresent(handler - handler.handle(req)); } }逐行拆解makeRequest的流水线逻辑buildChain()在构造器中完成链的装配将三个处理者放入ListRequestHandler.stream().sorted(Comparator.comparing(RequestHandler::getPriority))按优先级升序排序士兵 1 → 指挥官 2 → 军官 3.filter(handler - handler.canHandleRequest(req))依次筛出能处理该请求的处理者.findFirst()取优先级最高且能处理的那一个.ifPresent(handler - handler.handle(req))执行处理——只有真正处理时才会调用req.markHandled()。这种排序 过滤 取首的实现使得新增处理者、调整处理顺序都非常廉价只需在buildChain()中增删成员或修改getPriority()返回值即可无需改动分发逻辑。入口程序与运行输出入口程序 App.java 让兽人国王连续发出三条命令public static void main(String[] args) { var king new OrcKing(); king.makeRequest(new Request(RequestType.DEFEND_CASTLE, defend castle)); king.makeRequest(new Request(RequestType.TORTURE_PRISONER, torture prisoner)); king.makeRequest(new Request(RequestType.COLLECT_TAX, collect tax)); }对应的控制台输出Orc commander handling request defend castle Orc officer handling request torture prisoner Orc soldier handling request collect tax三条命令分别由链上三个不同级别的处理者接住直观展示了请求沿链流转、按能力匹配处理者的效果。类图与源码结构全景下图是本模块的 UML 类图PlantUML 源文件位于 chain-of-responsibility.urm.puml渲染图如下从类图与源码可以归纳出本模块的完整类结构均位于com.iluwatar.chain包类 / 接口角色关键成员RequestHandler接口抽象处理者canHandleRequest/getPriority/handle/nameOrcCommander具体处理者处理DEFEND_CASTLE优先级 2OrcOfficer具体处理者处理TORTURE_PRISONER优先级 3OrcSoldier具体处理者处理COLLECT_TAX优先级 1OrcKing链构建者 / 分发器持有ListRequestHandler handlersmakeRequest负责分发Request请求对象requestType、requestDescription、handled状态RequestType枚举请求类型DEFEND_CASTLE、TORTURE_PRISONER、COLLECT_TAXApp程序入口main方法发起三条命令关系要点OrcKing通过-handlers关联RequestHandler接口面向接口编程OrcCommander、OrcOfficer、OrcSoldier三个具体处理者都以虚线实现该接口Request通过requestType属性关联RequestType枚举。如何运行与验证本模块本模块是独立的 Maven 子模块见 chain-of-responsibility/pom.xml继承父项目com.iluwatar:java-design-patterns依赖 slf4j-api、logback-classic 与 junit-jupiter-engine并在maven-assembly-plugin中指定主类为com.iluwatar.chain.App。在仓库根目录下可执行以下命令查看运行结果# 运行责任链示例主程序 ./mvnw -pl chain-of-responsibility compile exec:java -Dexec.mainClasscom.iluwatar.chain.App # 运行该模块的全部单元测试 ./mvnw -pl chain-of-responsibility test本模块自带两组单元测试可用于验证模式行为OrcKingTest.java构造了覆盖全部三种RequestType的请求列表逐个交给OrcKing.makeRequest后断言request.isHandled()为真——即所有请求最终都能被链上某个处理者接住AppTest.java断言App.main执行过程中不抛出异常保证示例程序可稳定运行。何时使用责任链模式从本模式的意图出发当以下场景出现时应考虑使用责任链有多个对象可能处理同一个请求且处理者事先未知——处理者应由运行时的请求内容自动判定希望把请求发送给多个对象中的某一个但不想显式指定接收者——发送者与接收者完全解耦可处理请求的对象集合需要动态指定——链的成员与顺序可以按需调整而不影响调用方。真实世界中的责任链应用责任链模式在各类框架与中间件中广泛存在典型场景包括GUI 框架中的事件冒泡Event Bubbling一个事件可能被 UI 组件层级中的多个层次处理中间件框架请求依次穿过一条由多个处理对象组成的链如 Web 中间件管线日志框架消息可依次传给一系列 logger每个 logger 以不同方式处理如级别过滤、格式化、输出java.util.logging.Logger#log()日志记录逐级向上传递的机制即是责任链的体现javax.servlet.Filter#doFilter()Servlet 过滤器链让每个 Filter 决定放行还是拦截请求Apache Commons Chain专门为责任链模式提供的通用实现库。责任链模式的收益与代价收益Benefits降低耦合请求发送者无需知道最终处理请求的具体 handler提升职责分配的灵活性通过增删链成员或调整顺序即可改变请求的处理方式可设置默认兜底处理者当链上没有具体处理者能接住请求时可配置一个 catch-all handler 兜底避免请求落空。代价Trade-Offs调试与理解成本上升链越长越复杂请求的流转路径就越难一眼看清可能产生无人处理的悬空请求如果链中缺少兜底处理者请求会在遍历整条链后依然未被处理对照上文流程图中的Request unhandled分支存在性能隐患请求可能需依次穿过多个处理者才能命中正确的那个甚至始终找不到带来额外的遍历开销。针对无人处理问题本仓库示例通过OrcKingTest断言了三条命令全部被处理但在更复杂的链设计中建议显式追加一个兜底 handler如unknown request处理器或在makeRequest的ifPresent之外补充未处理分支。与其他设计模式的关系Command 命令模式可将请求封装为对象封装后的命令对象恰好适合沿责任链传递Composite 组合模式责任链常与组合模式搭配使用树的节点天然构成层次化的处理链Decorator 装饰器模式装饰器可以像责任链一样串联逐层包裹并增强行为——区别在于装饰器通常全部执行而责任链通常只由一个节点处理。参考资料与延伸阅读本文内容以本仓库 chain-of-responsibility 模块的 README、src/main/java/com/iluwatar/chain 下的全部源码、src/test 下的测试用例以及 etc 下的类图与流程图为准。责任链模式作为经典 GoF 行为型模式在以下经典著作中均有系统论述可作为延伸学习材料Design Patterns: Elements of Reusable Object-Oriented Software、Head First Design Patterns、Pattern-Oriented Software Architecture, Volume 1: A System of Patterns、Refactoring to Patterns与Pattern Languages of Program Design 3。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐Android Developer Roadmap与Chain of Responsibility模式请求处理链Android Developer Roadmap与Chain of Responsibility模式请求处理链 Android开发中请求处理逻辑的复杂性随移动开发教程CS-Notes 设计模式精讲责任链Chain of Responsibility模式原理与 Java 实现CS Notes 设计模式精讲责任链Chain of Responsibility模式原理与 Java 实现 责任链Chain of Responsib知识库文档教程Go职责链模式应用golang-design-pattern中的请求处理链构建Go职责链模式应用golang design pattern中的请求处理链构建 职责链模式解决的核心问题 在日常开发中你是否经常遇到需要多层审批的业务场景示例工程上一篇ConvNeXt模型剪枝后微调策略3个高效恢复性能方法指南下一篇CANN/cannbot-skills CSV公共字段与约定创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表