责任链模式:优雅处理复杂流程的设计艺术

引言

在软件设计中,我们经常会遇到需要按特定顺序处理请求的场景。例如,一个订单处理系统可能需要经过验证、付款、物流安排和客户通知等多个步骤。如果我们将这些步骤硬编码在一个方法中,代码将变得臃肿且难以维护。这时,责任链模式(Chain of Responsibility Pattern)就显示出了它的价值。

责任链模式是一种行为设计模式,它允许多个对象依次处理同一个请求,从而将请求的发送者与接收者解耦。本文将详细介绍责任链模式的核心概念、实现方法以及适用场景。

什么是责任链模式?

责任链模式是这样工作的:一个请求沿着一条预定义的对象链传递,直到有一个对象处理它或者请求到达链尾。每个处理者决定是自己处理请求还是将其传递给链中的下一个对象。

这种模式的美妙之处在于:请求的发送者不需要知道谁会处理这个请求,而每个处理者也只需要关注自己的职责,无需知道整个链的结构。

责任链模式的核心组件

  1. 抽象处理者(Handler): 定义了处理请求的接口,通常包含设置下一个处理者和处理请求的方法。
  2. 具体处理者(ConcreteHandler): 实现抽象处理者的接口,处理自己负责的请求,如果不能处理则传递给下一个处理者。
  3. 客户端(Client): 创建处理者对象并组成责任链,然后向链上的第一个处理者发送请求。

类图

下面是责任链模式的类图:

责任链模式的实现

让我们以一个订单处理系统为例,说明如何实现责任链模式:

1. 创建订单类

/*** 订单类 - 包含订单的基本信息和处理状态*/
public class Order {private int id;                  // 订单IDprivate double amount;           // 订单金额private String customerName;     // 客户名称private boolean isValidated;     // 订单是否已验证private boolean isPaymentProcessed; // 支付是否已处理private boolean isDeliveryArranged; // 配送是否已安排private boolean isNotificationSent;  // 通知是否已发送/*** 订单构造函数* @param id 订单ID* @param amount 订单金额* @param customerName 客户名称*/public Order(int id, double amount, String customerName) {this.id = id;this.amount = amount;this.customerName = customerName;this.isValidated = false;this.isPaymentProcessed = false;this.isDeliveryArranged = false;this.isNotificationSent = false;}// Getters and setterspublic int getId() {return id;}public double getAmount() {return amount;}public String getCustomerName() {return customerName;}public boolean isValidated() {return isValidated;}public void setValidated(boolean validated) {isValidated = validated;}public boolean isPaymentProcessed() {return isPaymentProcessed;}public void setPaymentProcessed(boolean paymentProcessed) {this.isPaymentProcessed = paymentProcessed;}public boolean isDeliveryArranged() {return isDeliveryArranged;}public void setDeliveryArranged(boolean deliveryArranged) {this.isDeliveryArranged = deliveryArranged;}public boolean isNotificationSent() {return isNotificationSent;}public void setNotificationSent(boolean notificationSent) {this.isNotificationSent = notificationSent;}@Overridepublic String toString() {return "Order{" +"id=" + id +", amount=" + amount +", customerName='" + customerName + '\'' +", isValidated=" + isValidated +", isPaymentProcessed=" + isPaymentProcessed +", isDeliveryArranged=" + isDeliveryArranged +", isNotificationSent=" + isNotificationSent +'}';}
}

2. 创建处理器接口

/*** 订单处理器抽象类 - 责任链模式的核心* 定义了处理订单的通用接口和设置下一个处理器的方法*/
public abstract class OrderHandler {protected OrderHandler nextHandler; // 责任链中的下一个处理器/*** 设置责任链中的下一个处理器* @param nextHandler 下一个处理器*/public void setNextHandler(OrderHandler nextHandler) {this.nextHandler = nextHandler;}/*** 处理订单的抽象方法,由具体的处理器实现* @param order 要处理的订单*/public abstract void handleOrder(Order order);
}

3. 实现具体的处理器类

订单验证处理器
/*** 订单验证处理器 - 责任链的第一环* 负责验证订单的基本信息是否有效*/
public class OrderValidationHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {System.out.println("OrderValidationHandler: 验证订单 #" + order.getId());// 验证订单逻辑if (order.getAmount() <= 0) {System.out.println("OrderValidationHandler: 订单金额无效,处理终止");return; // 终止责任链,不再继续处理}if (order.getCustomerName() == null || order.getCustomerName().isEmpty()) {System.out.println("OrderValidationHandler: 客户信息无效,处理终止");return; // 终止责任链,不再继续处理}// 标记为已验证order.setValidated(true);System.out.println("OrderValidationHandler: 订单 #" + order.getId() + " 已验证通过");// 传递给下一个处理器if (nextHandler != null) {nextHandler.handleOrder(order); // 继续责任链的处理流程}}
}
支付处理器
/*** 支付处理器 - 责任链的第二环* 负责处理订单的支付流程*/
public class PaymentProcessHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 检查订单是否已验证,确保责任链的顺序性if (!order.isValidated()) {System.out.println("PaymentProcessHandler: 订单 #" + order.getId() + " 未通过验证,无法处理支付");return; // 前置条件不满足,终止处理}System.out.println("PaymentProcessHandler: 处理订单 #" + order.getId() + " 的支付,金额: " + order.getAmount());// 模拟支付处理逻辑// 这里可以加入支付网关调用等实际业务逻辑boolean paymentSuccessful = processPayment(order);if (paymentSuccessful) {order.setPaymentProcessed(true);System.out.println("PaymentProcessHandler: 订单 #" + order.getId() + " 支付成功");// 传递给下一个处理器if (nextHandler != null) {nextHandler.handleOrder(order); // 继续责任链的处理流程}} else {System.out.println("PaymentProcessHandler: 订单 #" + order.getId() + " 支付失败,处理终止");// 支付失败,终止责任链}}/*** 处理支付的内部方法* @param order 要处理支付的订单* @return 支付是否成功*/private boolean processPayment(Order order) {// 模拟支付处理// 在实际应用中,这里会调用支付网关APIreturn order.getAmount() <= 10000; // 假设10000以上的订单需要额外审核}
}
配送安排处理器
/*** 配送安排处理器 - 责任链的第三环* 负责为已支付的订单安排配送*/
public class DeliveryArrangementHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 检查订单是否已支付,确保责任链的顺序性if (!order.isPaymentProcessed()) {System.out.println("DeliveryArrangementHandler: 订单 #" + order.getId() + " 未完成支付,无法安排配送");return; // 前置条件不满足,终止处理}System.out.println("DeliveryArrangementHandler: 为订单 #" + order.getId() + " 安排配送");// 模拟配送安排逻辑arrangeDelivery(order);order.setDeliveryArranged(true);System.out.println("DeliveryArrangementHandler: 订单 #" + order.getId() + " 已安排配送");// 传递给下一个处理器if (nextHandler != null) {nextHandler.handleOrder(order); // 继续责任链的处理流程}}/*** 安排配送的内部方法* @param order 要安排配送的订单*/private void arrangeDelivery(Order order) {// 模拟配送安排// 在实际应用中,这里会与物流系统对接System.out.println("DeliveryArrangementHandler: 正在为客户 " + order.getCustomerName() + " 安排递送服务");}
}
通知处理器
/*** 通知处理器 - 责任链的最后一环* 负责在订单处理完成后发送通知给客户*/
public class NotificationHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 检查订单是否已安排配送,确保责任链的顺序性if (!order.isDeliveryArranged()) {System.out.println("NotificationHandler: 订单 #" + order.getId() + " 未安排配送,无法发送通知");return; // 前置条件不满足,终止处理}System.out.println("NotificationHandler: 发送订单 #" + order.getId() + " 的通知");// 模拟发送通知逻辑sendNotification(order);order.setNotificationSent(true);System.out.println("NotificationHandler: 订单 #" + order.getId() + " 的通知已发送");// 完成处理,这是责任链的最后一环System.out.println("订单 #" + order.getId() + " 处理完成!");}/*** 发送通知的内部方法* @param order 要发送通知的订单*/private void sendNotification(Order order) {// 模拟发送通知// 在实际应用中,这里会调用邮件或短信服务System.out.println("NotificationHandler: 向客户 " + order.getCustomerName() + " 发送订单确认通知");}
}

4. 创建客户端测试类

/*** 订单处理器 - 客户端类* 负责构建和初始化责任链,并启动订单处理流程*/
public class OrderProcessor {private OrderHandler chain; // 责任链的起点/*** 构造函数,初始化责任链*/public OrderProcessor() {// 构建责任链buildOrderProcessingChain();}/*** 构建订单处理责任链* 设定处理器的顺序:验证 -> 支付 -> 配送 -> 通知*/private void buildOrderProcessingChain() {// 创建各个处理器OrderHandler validationHandler = new OrderValidationHandler();OrderHandler paymentHandler = new PaymentProcessHandler();OrderHandler deliveryHandler = new DeliveryArrangementHandler();OrderHandler notificationHandler = new NotificationHandler();// 设置处理器链,定义处理顺序validationHandler.setNextHandler(paymentHandler);paymentHandler.setNextHandler(deliveryHandler);deliveryHandler.setNextHandler(notificationHandler);// 设置责任链的起点this.chain = validationHandler;}/*** 处理订单的方法,将订单传入责任链的起点* @param order 要处理的订单*/public void processOrder(Order order) {System.out.println("开始处理订单 #" + order.getId());chain.handleOrder(order); // 启动责任链处理}
}

5. 主类用于运行示例

/*** 责任链模式演示类* 用于测试责任链在不同订单场景下的行为*/
public class ChainOfResponsibilityDemo {public static void main(String[] args) {// 创建订单处理器OrderProcessor processor = new OrderProcessor();// 测试案例1: 有效订单 - 应该完成所有处理步骤Order validOrder = new Order(1001, 1200.50, "张三");System.out.println("=== 处理有效订单 ===");processor.processOrder(validOrder);System.out.println("最终订单状态: " + validOrder);System.out.println();// 测试案例2: 金额无效的订单 - 应在验证阶段终止Order invalidAmountOrder = new Order(1002, 0, "李四");System.out.println("=== 处理金额无效的订单 ===");processor.processOrder(invalidAmountOrder);System.out.println("最终订单状态: " + invalidAmountOrder);System.out.println();// 测试案例3: 客户信息为空的订单 - 应在验证阶段终止Order noCustomerOrder = new Order(1003, 2500.75, "");System.out.println("=== 处理客户信息为空的订单 ===");processor.processOrder(noCustomerOrder);System.out.println("最终订单状态: " + noCustomerOrder);System.out.println();}
}

6. 测试结果

责任链模式的优点

  1. 降低耦合度: 发送者与接收者解耦,发送者不需要知道谁会处理请求。
  2. 增加灵活性: 可以动态地改变责任链的成员或者调整处理顺序。
  3. 单一职责: 每个处理者只关注自己的职责,符合单一职责原则。
  4. 开闭原则: 可以在不修改现有代码的情况下增加新的处理者,符合开闭原则。

责任链模式的缺点

  1. 性能考量: 请求可能需要经过多个处理者才能得到处理,增加了处理时间。
  2. 保证处理: 如果责任链设计不当,可能导致请求无法被处理。
  3. 调试困难: 请求的流向可能不明确,增加了调试难度。

责任链模式的应用场景

责任链模式适用于以下场景:

  1. 多个对象可以处理同一个请求,但具体由哪个对象处理在运行时确定
  2. 需要动态指定一组对象处理请求
  3. 不明确指定请求处理者的情况下,向多个对象中的一个提交请求

实际应用例子:

  • Web应用中的过滤器和拦截器
  • 日志记录系统的级别处理
  • 异常处理机制
  • 工作流系统中的审批流程

总结

责任链模式通过将请求沿着处理者链进行传递,实现了请求发送者与接收者之间的解耦。它不仅使代码更加整洁和模块化,还提高了系统的灵活性和可维护性。在处理复杂流程和事件传递时,责任链模式是一个非常有价值的设计工具。

当你的系统中出现一系列处理者,它们以特定顺序处理请求,且请求的处理流程灵活多变时,请考虑使用责任链模式。它将帮助你构建更加优雅和可扩展的系统架构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】玩转IIC之驱动MPU6050及姿态解算

目录 前言 一.MPU6050模块介绍 1.1MPU6050简介 1.2 MPU6050的引脚定义 1.3MPU6050寄存器解析 二.MPU6050驱动开发 2.1 配置寄存器 2.2对MPU6050寄存器进行读写 2.2.1 写入寄存器 2.2.2读取寄存器 2.3 初始化MPU6050 2.3.1 设置工作模式 2.3.2 配置采样率 2.3.3 启…

【ThreeJS Basics 09】Debug

文章目录 简介从 dat.GUI 到 lil-gui例子安装 lil-gui 并实例化不同类型的调整改变位置针对非属性的调整复选框颜色 功能/按钮调整几何形状文件夹调整 GUI宽度标题关闭文件夹隐藏按键切换 结论 简介 每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与…

【Pandas】pandas Series explode

Pandas2.2 Series Computations descriptive stats 方法描述Series.argsort([axis, kind, order, stable])用于返回 Series 中元素排序后的索引位置的方法Series.argmin([axis, skipna])用于返回 Series 中最小值索引位置的方法Series.argmax([axis, skipna])用于返回 Series…

电脑网络出现问题!简单的几种方法解除电脑飞行模式

在某些情况下&#xff0c;您可能需要关闭电脑上的飞行模式以便重新连接到 Wi-Fi、蓝牙或其他无线网络。本教程中简鹿办公将指导您如何在 Windows 和 macO S操作系统上解除飞行模式。 一、Windows 系统下解除飞行模式 通过快捷操作中心 步骤一&#xff1a;点击屏幕右下角的通知…

nature genetics | SCENT:单细胞多模态数据揭示组织特异性增强子基因图谱,并可识别致病等位基因

–https://doi.org/10.1038/s41588-024-01682-1 Tissue-specific enhancer–gene maps from multimodal single-cell data identify causal disease alleles 研究团队和单位 Alkes L. Price–Broad Institute of MIT and Harvard Soumya Raychaudhuri–Harvard Medical S…

MyBatis-Plus 与 Spring Boot 的最佳实践

在现代 Java 开发中,MyBatis-Plus 和 Spring Boot 的结合已经成为了一种非常流行的技术栈。MyBatis-Plus 是 MyBatis 的增强工具,提供了许多便捷的功能,而 Spring Boot 则简化了 Spring 应用的开发流程。本文将探讨如何将 MyBatis-Plus 与 Spring Boot 进行整合,并分享一些…

uploadlabs通关思路

目录 靶场准备 复现 pass-01 代码审计 执行逻辑 文件上传 方法一&#xff1a;直接修改或删除js脚本 方法二&#xff1a;修改文件后缀 pass-02 代码审计 文件上传 1. 思路 2. 实操 pass-03 代码审计 过程&#xff1a; 文件上传 pass-04 代码审计 文件上传 p…

AI编程工具节选

1、文心快码 百度基于文心大模型推出的一款智能编码助手&#xff0c; 官网地址&#xff1a;文心快码(Baidu Comate)更懂你的智能代码助手 2、通义灵码 阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff0c; 官网地址&#xff1a;通义灵码_你的智能编码助手-阿里云 …

目录扫描工具深度对比:Dirb、Dirsearch、DirBuster、Feroxbuster 与 Gobuster

✨ 前言 在网络安全测试与渗透测试中&#xff0c;目录扫描&#xff08;又称目录枚举&#xff09;是一项至关重要的技术。它用于发现 Web 服务器上未公开的隐藏目录和文件&#xff0c;这些资源可能包含敏感数据、配置文件甚至潜在漏洞&#xff0c;因而成为攻击者与安全研究人员…

“双碳”背景下,企业应该如何提升能源效率?

在当今竞争激烈的市场环境中&#xff0c;企业不仅需要优化成本&#xff0c;还需积极响应国家的能源政策&#xff0c;减少对环境的影响。提升工业能源效率正是实现这一双重目标的关键。中国近年来大力推进“双碳”目标&#xff08;碳达峰、碳中和&#xff09;&#xff0c;并出台…

无人机扩频技术对比!

一、技术原理与核心差异 FHSS&#xff08;跳频扩频&#xff09; 核心原理&#xff1a;通过伪随机序列控制载波频率在多个频点上快速跳变&#xff0c;收发双方需同步跳频序列。信号在某一时刻仅占用窄带频谱&#xff0c;但整体覆盖宽频带。 技术特点&#xff1a; 抗干扰…

当AI开始“思考“:拆解大模型训练与推理的秘密(以DeepSeek为例)

如果你用过deepseek&#xff0c;可能体验过它在几秒内编故事、写代码的震撼。但你是否想过&#xff0c;这种"智能输出"背后存在两种完全不同的底层机制&#xff1f;就像人类需要先学习知识&#xff08;训练&#xff09;才能考试答题&#xff08;推理&#xff09;&…

永洪科技深度分析实战,零售企业的销量预测

随着人工智能技术的不断发展&#xff0c;智能预测已经成为各个领域的重要应用之一。现在&#xff0c;智能预测技术已经广泛应用于金融、零售、医疗、能源等领域&#xff0c;为企业和个人提供决策支持。 智能预测技术通过分析大量的数据&#xff0c;利用机器学习和深度学习算法…

Vue项目通过内嵌iframe访问另一个vue页面,获取token适配后端鉴权(以内嵌若依项目举例)

1. 改造子Vue项目进行适配(ruoyi举例) (1) 在路由文件添加需要被外链的vue页面配置 // 若依项目的话是 router/index.js文件 {path: /contrast,component: () > import(/views/contrast/index),hidden: true },(2) 开放白名单 // 若依项目的话是 permission.js 文件 cons…

【DeepSeek】5分钟快速实现本地化部署教程

一、快捷部署 &#xff08;1&#xff09;下载ds大模型安装助手&#xff0c;下载后直接点击快速安装即可。 https://file-cdn-deepseek.fanqiesoft.cn/deepseek/deepseek_28348_st.exe &#xff08;2&#xff09;打开软件&#xff0c;点击立即激活 &#xff08;3&#xff09;选…

Linux第一课

如何在Windows系统上安装红帽Linux虚拟机 一:下载VNware 下载链接:Desktop Hypervisor Solutions | VMware 二:下载操作系统镜像文件 在阿里云开源镜像站下载(本文章下载 red hat 9.3) 阿里云开源镜像站链接:阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 三:创建虚拟机文…

语音分离:使用短时能量提取主声源

语音分离模型&#xff1a;mossfomer2 计算短时能量 def compute_short_time_energy(audio: np.ndarray, frame_size: int, hop_size: int) -> np.ndarray:"""计算音频信号的短时能量 将音频分为若干帧&#xff0c;每一帧长度为 frame_size, 帧与帧之间以 h…

【VUE】第二期——生命周期及工程化

目录 1 生命周期 1.1 介绍 1.2 钩子 2 可视化图表库 3 脚手架Vue CLI 3.1 使用步骤 3.2 项目目录介绍 3.3 main.js入口文件代码介绍 4 组件化开发 4.1 组件 4.2 普通组件注册 4.2.1 局部注册 4.2.2 全局注册 1 生命周期 1.1 介绍 Vue生命周期&#xff1a;就是…

SyntaxError: Unexpected keyword ‘else‘

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

Spring Boot静态资源访问顺序

在 Spring Boot 中&#xff0c;static 和 public 目录都用于存放静态资源&#xff08;如 HTML、CSS、JavaScript、图片等文件&#xff09;&#xff0c;但它们在使用上有一些细微的区别。以下是它们的详细对比&#xff1a; 1. 默认优先级 Spring Boot 会按照以下优先级加载静态…