news 2026/10/1 8:47:49

Java 责任链模式实战:基于 java-design-patterns 仓库的请求处理链完整解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 责任链模式实战:基于 java-design-patterns 仓库的请求处理链完整解析
  • 示例工程
  • 教程

【免费下载链接】java-design-patterns

Design patterns implemented in Java

项目地址:https://gitcode.com/GitHub_Trending/ja/java-design-patterns
点击查看免费下载

导读

责任链(Chain of Responsibility)是 Gang of Four 提出的经典行为型设计模式之一,其核心价值在于将请求的发送者与接收者解耦:允许多个对象依次获得处理请求的机会,请求沿着链条传递,直到被某个合适的处理器接收。本文以 java-design-patterns 仓库中chain-of-responsibility模块(源码位于 chain-of-responsibility/src/main/java/com/iluwatar/chain)为蓝本,结合官方阿拉伯语文档 localization/ar/chain-of-responsibility/README.md 的核心内容,从模式意图、代码实现、类图结构、适用场景到优缺点与关联模式,带你完整掌握责任链模式在 Java 中的落地写法。读完本文,你将能够独立实现一套可动态调整处理顺序、按需增加处理器的请求分发机制。

模式概览:责任链是什么

其他名称

责任链模式在不同资料中也被称为:

  • 命令链(Chain of Command)
  • 对象链(Chain of Objects)
  • 责任链(Responsibility Chain)

模式意图

责任链模式通过给予多个对象处理请求的机会,将请求发送者与其接收者解耦。接收对象被串联成一条链,请求沿着链传递,直到某个对象将其处理完毕。发送者无需知道"谁"会处理请求,只需发出请求即可。

现实世界类比

文档给出了一个生动的例子:兽人国王(Orc King)大声向军队下达命令,离他最近的、依次响应的是指挥官(Commander)、军官(Officer)与士兵(Soldier)。指挥官、军官、士兵共同构成了一条"责任链"——每条命令沿链传递,直到找到能处理它的那个人。

用简单的话说:该模式帮助构建一条对象链,请求从一端进入,从一个对象流转到另一个对象,直到遇到合适的处理器为止。

权威定义

在面向对象设计中,责任链模式由一组命令对象源和一系列处理对象组成。每个处理对象都包含定义其可处理命令类型的逻辑;无法处理的请求则被传递给链中的下一个处理对象。

程序化示例:兽人军团的请求处理链

本仓库中chain-of-responsibility模块用"兽人国王下达命令、军团分级响应"的故事演示了该模式,共包含 8 个 Java 文件。下面按职责逐一拆解。

第一步:请求载体Request与RequestType

请求对象封装了被传递的信息,其源码见 Request.java:

@Getter 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(); } }

要点说明:

  • requestType:请求类型,链上每个处理器通过它判断自己"是否能够处理"该请求;
  • requestDescription:请求描述文本,同时作为toString()的返回值,便于日志输出;
  • handled与markHandled():记录请求是否已被处理。源码注释明确说明该状态只能从"未处理"单向变为"已处理",不存在"撤销处理"的路径;
  • 构造器通过Objects.requireNonNull强制要求类型与描述非空,避免空指针隐患。

请求类型定义在 RequestType.java:

public enum RequestType { DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX }

本示例只有三种请求:保卫城堡、拷问囚犯、征收赋税。

第二步:处理器抽象RequestHandler

所有处理器实现统一接口 RequestHandler.java,接口定义了四个方法:

public interface RequestHandler { boolean canHandleRequest(Request req); int getPriority(); void handle(Request req); String name(); }
方法职责
canHandleRequest(Request)判断当前处理器是否有能力处理该请求
getPriority()返回处理优先级(用于决定链中调用顺序)
handle(Request)实际执行处理逻辑
name()返回处理器名称,用于日志输出

第三步:三个具体处理器

指挥官 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.java 与士兵 OrcSoldier.java 的定义方式与指挥官完全一致,只是处理对象和元数据不同,三者配置对比如下:

处理器可处理的请求类型优先级名称
OrcCommanderDEFEND_CASTLE2Orc commander
OrcOfficerTORTURE_PRISONER3Orc officer
OrcSoldierCOLLECT_TAX1Orc soldier

三个类均通过 Lombok 的@Slf4j注解获得LOGGER,并在handle()中先调用req.markHandled()标记请求已处理,再输出日志。

第四步:组装链条OrcKing

国王 OrcKing.java 负责构建链条并发起请求:

public class OrcKing { private List<RequestHandler> 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)); } }

请求分发逻辑可以拆解为四步流水线:

  1. buildChain():将三个处理器放入List<RequestHandler>完成链条组装;
  2. sorted(...):按getPriority()升序排列,确保处理顺序可控;
  3. filter(...):过滤出所有"有能力处理该请求"的处理器;
  4. findFirst().ifPresent(...):取第一个符合条件的处理器执行handle()。

需要特别指出的是:从源码结构看,本实现并未采用经典责任链"每个处理器持有下一个处理器引用"的链表式写法,而是由OrcKing统一持有处理器列表,通过"优先级排序 + 能力过滤 + 取首个"的方式完成请求路由,达到的效果与责任链一致——发送者不知道也不关心最终由谁处理。

第五步:运行演示与输出

程序入口 App.java 演示了完整调用:

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"

三种不同类型的请求分别被链条中对应的处理器接收,全程无需在调用方指定接收者。

类图结构

OrcKing.java 持有RequestHandler列表,三个具体处理器实现RequestHandler接口,Request依赖RequestType,整体结构如下图所示(图片来源 chain-of-responsibility/etc/chain-of-responsibility.urm.png,其 PlantUML 源文件见 chain-of-responsibility/etc/chain-of-responsibility.urm.puml):

责任链模式类图:OrcKing 持有 RequestHandler 列表,OrcCommander、OrcOfficer、OrcSoldier 实现 RequestHandler 接口

源码级实现细节与测试验证

测试用例印证"请求必被处理"

模块配套的单元测试 OrcKingTest.java 覆盖了所有请求类型,断言国王发出的每一个请求最终都被标记为已处理:

class OrcKingTest { private static final List<Request> REQUESTS = List.of( new Request(RequestType.DEFEND_CASTLE, "Don't let the barbarians enter my castle!!"), new Request(RequestType.TORTURE_PRISONER, "Don't just stand there, tickle him!"), new Request(RequestType.COLLECT_TAX, "Don't steal, the King hates competition ...")); @Test void testMakeRequest() { final var king = new OrcKing(); REQUESTS.forEach(request -> { king.makeRequest(request); assertTrue(request.isHandled(), "Expected all requests from King to be handled, but [" + request + "] was not!"); }); } }

该测试验证了责任链的核心承诺:只要链条中存在能处理该请求的处理器,请求就不会丢失,且测试中的三类请求恰好与三个处理器一一对应。

模式在仓库中的定位

  • 模块分类:Behavioral(行为型)模式;
  • 核心标签:Gang of Four、Decoupling(解耦)、Event-driven、Messaging;
  • 模块完整英文文档见 chain-of-responsibility/README.md,阿拉伯语译文即本文所依托的 localization/ar/chain-of-responsibility/README.md。

何时使用责任链模式

根据官方文档,当出现以下情况时应考虑使用责任链模式:

  • 多个对象都可能处理同一个请求,且处理器无法预先确定——应让系统自动判定由谁处理;
  • 希望向若干对象中的某一个发出请求,但不想显式指定接收者;
  • 能够处理请求的对象集合需要动态确定(例如运行时增删处理器或调整顺序)。

反之,如果链条很长且结构复杂,导致流程难以追踪,或需要严格保证每个请求都有处理结果,则需要谨慎评估是否引入"兜底处理器"。

现实世界中的典型应用

责任链模式在主流框架中随处可见,文档列举了以下典型场景:

  • GUI 框架中的事件冒泡:一个事件可能在 UI 组件层级的多层中被处理;
  • 中间件框架:请求依次穿过一串处理对象;
  • 日志框架:消息可经过一串 Logger,每个 Logger 以不同方式处理;
  • java.util.logging.Logger#log():日志记录按级别沿 logger 层级向上传递;
  • Apache Commons Chain:基于责任链思想的通用链式处理框架;
  • javax.servlet.Filter#doFilter():Servlet 过滤器链,每个 Filter 处理后调用chain.doFilter()将请求传给下一个,是责任链模式的教科书级应用。

优点与代价

优点

  • 降低耦合:请求发送者无需知道具体由哪个处理器处理请求;
  • 职责分配更灵活:可以通过改变链条成员与排列顺序,增删或调整对请求的处理责任;
  • 支持默认处理器:当链中没有具体处理器能处理请求时,可以设置一个兜底的默认处理器。

代价

  • 调试与理解成本高:当链条又长又复杂时,追踪请求的流转路径会比较困难;
  • 请求可能无人处理:如果链条中没有"全捕获"(catch-all)处理器,请求可能最终处于未处理状态;
  • 存在性能开销:请求可能经过多个处理器才能命中目标,甚至遍历整条链仍找不到处理器。

与其他模式的关系

责任链模式常与其他行为型/结构型模式配合使用,本仓库中对应的模式模块可作为对照学习材料:

  • 命令模式:可将请求封装为对象,再沿责任链传递;
  • 组合模式:责任链常与组合模式结合使用(例如 UI 组件树与事件冒泡);
  • 装饰器模式:装饰器可以像责任链中的职责一样串联使用。

参考资料

官方文档引用的经典著作如下,可作为深入学习的延伸阅读:

  • Design Patterns: Elements of Reusable Object-Oriented Software(GoF 四人组原著)
  • Head First Design Patterns
  • Pattern-Oriented Software Architecture, Volume 1: A System of Patterns
  • Refactoring to Patterns
  • Pattern Languages of Program Design 3

小结

通过本仓库chain-of-responsibility模块,我们完整走通了责任链模式的"意图 → 建模 → 实现 → 测试 → 应用"全链路:Request封装请求状态,RequestHandler统一处理器契约,OrcCommander/OrcOfficer/OrcSoldier各司其职,OrcKing负责组装链条并按优先级路由请求。这套结构清晰、可测试、可动态调整的实现,可直接迁移到中间件、过滤器、事件分发等真实业务场景中。

  • 示例工程
  • 教程

【免费下载链接】java-design-patterns

Design patterns implemented in Java

项目地址:https://gitcode.com/GitHub_Trending/ja/java-design-patterns
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 8:46:58

Photoshop - 将Photoshop图像置入其他应用程序

Photoshop提供许多可帮助在其它应用程序中使用图像的功能。由于Adobe产品之间是紧密集成的&#xff0c;因此许多Adobe应用程序都可以直接导入Photoshop (PSD)格式文件并使用图层&#xff0c;图层样式&#xff0c;蒙版&#xff0c;透明度及效果等Photoshop功能。一&#xff0e;为…

作者头像 李华
网站建设 2026/10/1 8:46:57

基于Springboot宠物一站式服务平台【附源码+文档】

&#x1f495;&#x1f495;作者&#xff1a; 米罗学长 &#x1f495;&#x1f495;个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 &#x1f495;&#x1f495;各类成品Java毕设 。ssm&#xff0c;springboot&#xff0c;vue等项目&#xff0…

作者头像 李华