23种设计模式-行为型模式-责任链
文章目录
- 简介
- 问题
- 解决
- 代码
- 核心改进点:
- 总结
简介
责任链是一种行为设计模式,允许你把请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
问题
假如你正在开发一个订单系统。 你希望限制系统访问,只允许认证用户创建订单。 而管理员拥有所有订单的完全访问权限。
按照一般的开发思路,你会依次执行这些检查。 只要接收到包含用户凭据的请求,系统就可以尝试认证。 如果认证失败, 那就没有必要再进行后续检查了。如下图。

接着,关于认证检查的需求越来越多。比如为了不让原始数据直接传递到订单系统,需要在认证之后清理请求中的数据;比如为了对暴力密码破解或者爬虫请求进行限流,又需要在认证之后增加过滤来自同一 IP 地址的重复请求逻辑;比如为了提高系统响应速度,降低系统负载,又需要在请求发送给系统之前检查有没有缓存结果,如果没有才会把请求发送给系统。如下图,这部分逻辑就会越来越多,越来越混乱。

而且,修改某个检查步骤可能也会影响其他的检查步骤。 尤其是当你希望复用这些检查步骤来保护其他系统时,你只能复制部分代码, 因为这些系统只需要部分检查步骤。
解决
与许多其他行为设计模式一样, 责任链会把 特定行为转换成 叫做处理者的独立对象。 在上面示例里, 每个检查步骤都可以被抽取成仅有单个方法的类, 并执行检查操作。 请求和对应数据会被作为参数传递给这个方法。
这个模式建议你把这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于下一个处理者的引用。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直到所有处理者都有机会对他进行处理。
更重要的是: 处理者可以决定不再沿着链传递请求, 这就可以高效地取消所有后面的处理步骤。
在我们的订单系统示例中, 处理者会在进行请求处理工作后决定要不要继续沿着链传递请求。 如果请求中包含正确的数据, 所有处理者都会执行自己的主要行为, 无论这个行为是身份验证还是数据缓存。

不过还有一种稍微不同的方式 (也是更经典一种), 那就是处理者接收到请求后自己决定是否能够对其进行处理。 如果自己能够处理, 处理者就不再继续传递请求。 因此在这种情况下, 每个请求要么最多有一个处理者进行处理, 要么没有任何处理者进行处理。 在处理图形用户界面元素栈中的事件时, 这种方式非常常见。另外,其实很多设计模式都是从很早用Java写客户端界面引出的解决方案。
代码
// Handler接口定义处理契约
public interface Handler {void handle(Request request) throws AuthException;
}// BaseHandler实现链式传递逻辑
public abstract class BaseHandler implements Handler {private Handler next;public BaseHandler setNext(Handler next) {this.next = next;return this;}protected void passToNext(Request request) throws AuthException {if (next != null) next.handle(request); // 核心链式调用逻辑}
}// 具体处理者1:用户认证
class UserAuthHandler extends BaseHandler {@Overridepublic void handle(Request request) throws AuthException {if (!validateUser(request.getUserId())) {throw new AuthException("用户未登录");}passToNext(request); // 验证成功移交后续处理}
}// 具体处理者2:权限校验
class PermissionHandler extends BaseHandler {@Override public void handle(Request request) throws AuthException {if (!checkAdminPermission(request.getUserId())) {throw new PermissionException("权限不足");}passToNext(request);}
}// Client动态组合处理链
public class OrderService {private Handler chain;public OrderService() {this.chain = new UserAuthHandler().setNext(new PermissionHandler()); // 灵活配置处理顺序}public void createOrder(Request request) {chain.handle(request); // 统一入口触发处理链// 执行业务逻辑...}
}
核心改进点:
- 解耦检查逻辑:每个安全检查独立成类,通过setNext组合链式结构
- 动态扩展性:新增日志检查仅需创建LogHandler并插入链中任意位置
- 复用性增强:在PaymentService中可重用UserAuthHandler而不需要重复验证代码
总结

- (Handler)声明了所有具体处理者的通用接口。这个接口通常只包含单个方法,用于请求处理,但有时它还会包含一个设置链上 下一个处理者 的方法。
- (Base Handler)是一个可选的类,你可以把所有处理者共用的样本代码放在里面。 通常情况下,这个类里定义了一个保存下个处理者引用的成员变量。客户端可以把下个处理者传递给上个处理者的构造函数或用setter方法 来创建链。这个类还可以实现默认的处理行为: 比如确定下个处理者存在后再把请求传递给它。
- (Concrete Handlers)包含处理请求的实际代码。每 个处理者接收到请求后,都必须决定要不要处理,以及要不要沿 着链传递请求。 处理者通常是独立并且不可变的,需要通过构造函数一次性地获得 所有必要的数据。
- (Client) 可根据程序逻辑一次性或者动态地生成链。 需要注意一下,请求可以发送给链上的任意一个处理者,不一定是第一个处理者。
相关文章:
23种设计模式-行为型模式-责任链
文章目录 简介问题解决代码核心改进点: 总结 简介 责任链是一种行为设计模式,允许你把请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。 问题 假如你正在开发一个订单系统。…...
git commit Message 插件解释说明
- feat - 一项新功能 - fix - 一个错误修复 - docs - 仅文档更改 - style - 不影响代码含义的更改(空白、格式化、缺少分号等) - refactor - 既不修复错误也不添加功能的代码更改 - perf - 提高性能的代码更改 - build - 影响构建系统或外部依赖项…...
推荐系统(二十一):基于MaskNet的商品推荐CTR模型实现
MaskNet 是微博团队 2021 年提出的 CTR 预测模型,相关论文:《MaskNet: Introducing Feature-Wise Multiplication to CTR Ranking Models by Instance-Guided Mask》。MaskNet 通过掩码自注意力机制,在推荐系统中实现了高效且鲁棒的特征交互学习,特别适用于需处理长序列及噪…...
OpenCV 从入门到精通(day_04)
1. 绘制图像轮廓 1.1 什么是轮廓 轮廓是一系列相连的点组成的曲线,代表了物体的基本外形。相对于边缘,轮廓是连续的,边缘不一定连续,如下图所示。其实边缘主要是作为图像的特征使用,比如可以用边缘特征可以区分脸和手…...
多模态学习(八):2022 TPAMI——U2Fusion: A Unified Unsupervised Image Fusion Network
论文链接:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber9151265 目录 一.摘要 1.1 摘要翻译 1.2 摘要解析 二.Introduction 2.1 Introduciton翻译 2.2 Introduction 解析 三. related work 3.1 related work翻译 3.2 relate work解析 四…...
JavaEE-0403学习记录
通过前期准备后,项目已经能够成功运行: 1、在文件UserMapper.java中添加如下代码: List<User> selectUSerByIdDynamic(User user); 2、在文件UserMapper.xml中添加如下代码: <select id"selectUSerByIdDynamic&quo…...
图像处理:使用Numpy和OpenCV实现傅里叶和逆傅里叶变换
文章目录 1、什么是傅里叶变换及其基础理论 1.1 傅里叶变换 1.2 基础理论 2. Numpy 实现傅里叶和逆傅里叶变换 2.1 Numpy 实现傅里叶变换 2.2 实现逆傅里叶变换 2.3 高通滤波示例 3. OpenCV 实现傅里叶变换和逆傅里叶变换及低通滤波示例 3.1 OpenCV 实现傅里叶变换 3.2 实现逆傅…...
洛谷题单2-P5715 【深基3.例8】三位数排序-python-流程图重构
题目描述 给出三个整数 a , b , c ( 0 ≤ a , b , c ≤ 100 ) a,b,c(0\le a,b,c \le 100) a,b,c(0≤a,b,c≤100),要求把这三位整数从小到大排序。 输入格式 输入三个整数 a , b , c a,b,c a,b,c,以空格隔开。 输出格式 输出一行,三个整…...
RNN模型与NLP应用——(7/9)机器翻译与Seq2Seq模型
声明: 本文基于哔站博主【Shusenwang】的视频课程【RNN模型及NLP应用】,结合自身的理解所作,旨在帮助大家了解学习NLP自然语言处理基础知识。配合着视频课程学习效果更佳。 材料来源:【Shusenwang】的视频课程【RNN模型及NLP应用…...
使用YoloV5和Mediapipe实现——上课玩手机检测(附完整源码)
目录 效果展示 应用场景举例 1. 课堂或考试监控(看到这个学生党还会爱我吗) 2. 驾驶安全监控(防止开车玩手机) 3. 企业办公管理(防止工作时间玩手机) 4. 监狱、戒毒所、特殊场所安保 5. 家长监管&am…...
XT-912在热交换站的应用
热网监控需求 随着国民经济的不断进步和人民生活水平日益提高,社会对环境的要求越来越高。近年来国家大力提倡城镇集中供热,改变原来各单位、各片区自己供热、单独建立锅炉房给城市带来的污染,由城市外围的一个或者多个热源厂提供热源&#…...
语文常识推翻百年“R完备、封闭”论
语文常识推翻百年“R完备、封闭”论 黄小宁 李四光:迷信权威等于扼杀智慧。语文常识表明从西方传进来的数学存在重大错误:将无穷多各异数轴误为同一轴。 复平面z各点z的对应点zk的全体是zk平面。z面平移变换为zk(k是非1正实常数…...
解决backtrader框架下日志ValueError: I/O operation on closed file.报错(jupyternotebook)
解决办法: 禁用 IPython 内核的日志重定向 在 IPython 环境下,内核可能会对日志进行重定向,从而引发问题。你可以尝试在运行代码之前禁用 IPython 的日志重定向: import logging# 禁用IPython内核的日志重定向 logging.getLogg…...
基于Docker容器部署DeepSeek-R1-Distill-Qwen-7B
首先打开魔搭社区,然后搜索DeepSeek-R1-Distill-Qwen-7B,进入详情页 官方推荐使用vllm来启动,但是手动搭建vllm环境容易出各种问题,我们这里直接找一个vllm的Docker镜像 一、拉取镜像 docker pull vllm/vllm-openai 如果拉取不…...
UART双向通信实现(序列机)
前言 UART(通用异步收发传输器)是一种串行通信协议,用于在电子设备之间进行数据传输。RS232是UART协议的一种常见实现标准,广泛应用于计算机和外围设备之间的通信。它定义了串行数据的传输格式和电气特性,以确…...
CentOS 7 全流程部署Magic-PDF数据清洗工具(附GPU加速方案)
CentOS 7 全流程部署Magic-PDF数据清洗工具(附GPU加速方案) 一、环境准备与方案选型 1.1 硬件要求 配置项最低要求推荐配置CPU4核8核内存8GB16GB存储50GBSSD/NVMeGPU可选NVIDIA T4 1.2 系统环境检查 # 查看系统版本 cat /etc/redhat-release# 检查G…...
2.1 路径问题专题:LeetCode 62. 不同路径
动态规划解决LeetCode 62题:不同路径问题 1. 题目链接 LeetCode 62. 不同路径 2. 题目描述 一个机器人位于一个 m x n 网格的左上角(起点标记为“Start”)。机器人每次只能向右或向下移动一步。机器人试图达到网格的右下角(标…...
“*(单星号)”和“**(双星号)”在Python中的灵活运用
在Python中,*和**是两个重要的运算符,它们具有不同的用途。 一、*(单星号) 1、*(单星号)作为乘法运算符 2、*(单星号) 用于解包序列或可迭代对象 用于解包序列或可迭代对象&…...
LabVIEW多线程
在 LabVIEW 中,多线程编程是提升程序执行效率的关键手段,尤其是在需要并行处理数据采集、控制执行和用户界面交互的场景下。LabVIEW 本身是基于数据流(Dataflow)的编程语言,天然支持多线程,但要高效利用多线…...
ctfshow _萌新 萌新_密码篇
萌新_密码1 先对密文进行 Hex 解码,得到了 S1lkZjBhM2ViZDVjNGRjMTYwLUV7ZmI2M2VlMDI5OGI4ZjRkOH0 再进行 base64 解码,得到了 KYdf0a3ebd5c4dc160-E{fb63ee0298b8f4d8} 再进行栅栏解码,得到了 flag KEY{dffb06a33eeeb0d259c84bd8cf146d08…...
Transformer架构详解:从Encoder到Decoder的完整旅程
引言:从Self-Attention到完整架构 在上一篇文章中,我们深入剖析了Self-Attention机制的核心原理。然而,Transformer的魅力远不止于此——其Encoder-Decoder架构通过巧妙的模块化设计,实现了从机器翻译到文本生成的广泛能力。本文…...
蓝桥杯2024省赛PythonB组——日期问题
题目链接: https://www.lanqiao.cn/problems/103/learning/?page1&first_category_id1&name%E6%97%A5%E6%9C%9F%E9%97%AE%E9%A2%98 题目内容: 解题思路 import os import sys# 请在此输入您的代码 from datetime import datetime date_str input().str…...
带头结点 的单链表插入方法(头插法与尾插法)
带头结点的单链表插入方法(头插法与尾插法) 在单链表的操作中,插入是最常见的操作之一,本文介绍 带头结点的单链表 如何实现 后插法 和 前插法(包括 插入法 和 后插数据交换法),并提供完整的 C …...
Opencv之dilib库:表情识别
一、简介 在计算机视觉领域,表情识别是一个既有趣又具有挑战性的任务。它在人机交互、情感分析、安防监控等众多领域都有着广泛的应用前景。本文将详细介绍如何使用 Python 中的 OpenCV 库和 Dlib 库来实现一个简单的实时表情识别系统。 二、实现原理 表情识别系统…...
基于web的生产过程执行管理系统(源码+lw+部署文档+讲解),源码可白嫖!
摘要 随着世界经济信息化、全球化的到来和电子商务的飞速发展,推动了很多行业的改革。若想达到安全,快捷的目的,就需要拥有信息化的组织和管理模式,建立一套合理、畅通、高效的线上管理系统。当前的生产过程执行管理存在管理效率…...
C++:继承+菱形虚拟继承的一箭双雕
目录 一、继承概念与定义 1.1、什么是继承? 1.2、继承定义 二、继承关系与访问限定符 2.1、继承方式 三、基类与派生类对象的赋值转换 3.1、向上转型 3.2、对象切片 四、继承中的作用域 4.1、隐藏 五、派生类中的成员函数 5.1、构造与析构 六、继承与友…...
网络:华为数通HCIA学习:静态路由基础
文章目录 前言静态路由基础静态路由应用场景 静态路由配置静态路由在串行网络的配置静态路由在以太网中的配置 负载分担配置验证 路由备份(浮动静态路由)配置验证 缺省路由配置验证 总结 华为HCIA 基础实验-静态路由 & eNSP静态路由 基础…...
CFResNet鸟类识别:原网络基础上改进算法
本文为为🔗365天深度学习训练营内部文章 原作者:K同学啊 先放一张ResNet50模型的鸟类识别结果图 一 ResNetSE-NetBN import matplotlib.pyplot as plt import tensorflow as tf import warnings as w w.filterwarnings(ignore) # 支持中文 plt.rcP…...
C++ | 文件读写(ofstream/ifstream/fstream)
一、C文件操作核心类 C标准库通过<fstream>提供了强大的文件操作支持,主要包含三个关键类: 类名描述典型用途ofstream输出文件流(Output File Stream)文件写入操作ifstream输入文件流(Input File Stream&#…...
11_常用函数
文章目录 一、概述二、字符函数2.1、获取字符串所占字节数2.2、获取字符个数2.3、拼接字符串2.4、大小写转换2.5、获取子串2.6、获取子串第一次出现的索引2.7、去除字符串前后子字符串2.7.1、去掉左侧空格2.7.2、去掉右侧空格 2.8、左右填充2.9、字符串替换 三、数学函数3.1、四…...
