当前位置: 首页 > news >正文

设计模式之责任链的通用实践思考

责任链模式通常一般用在方法的拦截、监控、统计方面,比较典型的就是Spring的AOP拦截。
但写一些小的基础能力框架的时候,用AOP比较中,所以一般都是自己针对特定的功能写一些定制的责任链工具类,不太喜欢总是做一些定制化的东西,想着能不能简单定义一套标准,基于标准能够快速实现责任链的能力?

1、定义简单的链路控制类

该类是一套标准的控制类,主要负责流转链路执行走向
其中Supplier中是目标的执行方法
T 代表接口的标记也就是第二点的实现

public class SampleBaseFilterChain<T extends SimpleChainFilterService> {/*** 拦截器*/private final List<T> functionFilters;/*** 具体的执行方法*/private final Supplier<Object> supplier;private int index = 0;public SampleBaseFilterChain(List<T> functionFilters, Supplier<Object> supplier) {this.functionFilters = functionFilters;this.supplier = supplier;}// 该方法是为了方便在Spring的IOC容器中直接根据类对象,从容器中获取相应的集合.public SampleBaseFilterChain(Class<T> clazz, Supplier<Object> supplier) {this.functionFilters = SpringUtils.getBeansOfType(clazz).values().stream().toList();this.supplier = supplier;}public Object doFilter(Object... objects) {if (CollectionUtils.isEmpty(functionFilters) || functionFilters.size() == index) {return supplier.get();}return functionFilters.get(index++).doFilter(this, objects);}}

2、定义接口标准

这部分接口太过于抽象,比如你不知道参数具体是啥,可能需要针对下层实现才知道。

public interface SimpleChainFilterService {Object doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, Object... obj);
}

基于以上两点基本上确定了控制器和顶层接口的定义,该怎么玩呢?

@Testpublic void doFilter() {List<SimpleChainFilterService> chainList = new ArrayList<>();chainList.add((chain, obj) -> {System.out.println("A-start-" + obj[0]);return chain.doFilter(obj);});chainList.add((chain, obj) -> {final Object o = chain.doFilter(obj);System.out.println("B-end-" + obj[0]);return o;});chainList.add((chain, obj) -> {System.out.println("C-start-" + obj[1]);final Object o = chain.doFilter(obj);System.out.println("C-end-" + obj[1]);return o;});SampleBaseFilterChain<SimpleChainFilterService> sampleFilterChain = new SampleBaseFilterChain<>(chainList, () -> "ok");final Object o = sampleFilterChain.doFilter("哈哈", 1);System.out.println("得到结果:" + o);}

打印结果:

A-start-哈哈
C-start-1
C-end-1
B-end-哈哈
得到结果:ok

3、接口标准优化

对于第二点的接口,太过于抽象,无法知道接口的具体参数,这对后续使用者实现来说会很麻烦。
这个时候,你可以针对特定的业务标准在下沉一层。
比如需要针对登录进行拦截

public interface  LoginChain extends SimpleChainFilterService {@Overridedefault Object doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, Object... obj) {return doFilter(chain, (String) obj[0], (int) obj[1]);}public String doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, String username, int id);
}

使用方式:

// 前置拦截
List<LoginChain1> chainList1 = new ArrayList<>();
chainList1.add((chain, username, id) -> {System.out.println("login-start-" + username + "\t" + id);return chain.doFilter(username, id).toString();
});// 后置拦截
chainList1.add((chain, username, id) -> {final String result = chain.doFilter(username, id).toString();System.out.println("login-end-" + username + "\t" + id);return result;
});SampleBaseFilterChain<LoginChain1> sampleFilterChain = new SampleBaseFilterChain<>(chainList1, () -> {System.out.println("ok");return "ok";
});final Object o = sampleFilterChain.doFilter("哈哈", 1);
System.out.println("得到结果:" + o);
login-start-哈哈	1
ok
login-end-哈哈	1
得到结果:ok

基于以上的定义,我们只需要编写SimpleChainFilterService实现即可,通过使用SampleBaseFilterChain 来触发控制流程的流转,就行了,不用每套责任链都要重写接口和控制链。

以上为个人实践思考,如果你有更好的方式,欢迎交流学习~

相关文章:

设计模式之责任链的通用实践思考

责任链模式通常一般用在方法的拦截、监控、统计方面&#xff0c;比较典型的就是Spring的AOP拦截。 但写一些小的基础能力框架的时候&#xff0c;用AOP比较中&#xff0c;所以一般都是自己针对特定的功能写一些定制的责任链工具类&#xff0c;不太喜欢总是做一些定制化的东西&am…...

前端用canvas绘图并支持下载

1.根据数据绘制饼图 /** 绘制环形图 */ const drawPieCharts () > {const {canWithdrawalPriceFront,noWithdrawalPriceFront,haveWithdrawalPriceFront,} this.state;const myCanvas this.cavasRef.current;// ts-ignoreconst ctx myCanvas.getContext(2d);if (ctx) {…...

【Mac】Homebrew

1、Homebrew 简介 官网地址&#xff1a;https://brew.sh Homebrew 是一款Mac OS平台下的软件包管理工具&#xff0c;拥有安装、卸载、更新、查看、搜索等很多实用的功能。 Homebrew 主要有四个部分组成: brew、homebrew-core 、homebrew-bottles、homebrew-cask。 源说明br…...

Python笔记之线程库threading

Python笔记之线程库threading 参考博文 Python多线程笔记——简单函数版和类实现版 code review! Python 的 threading 库用于在程序中创建和管理线程。线程允许程序并发执行多个任务。以下是 threading 库的详解和一些简洁示例。 基本概念 线程&#xff1a;在一个进程中&a…...

go 包管理

Go语言所依赖的所有的第三方库都放在GOPATH目录下面 gomodule是Go语言默认的依赖管理工具 Modules是相关Go包的集合&#xff0c;是源代码交换和版本控制的单元&#xff0c;用于指定使用哪些源文件 GO111MODULEoff禁用gomodule&#xff0c;编译时从GOPATH和vendor文件夹中查找包…...

Js内建对象

数组解构 const arr ["1","2","3"]let a,b,c// 解构赋值 //将数组的第一个元素赋值给第一个变量&#xff0c;第二个元素赋值给第二个变量&#xff0c;依次类推[a,b,c] arr console.log(a,b,c) // 1 2 3 // 声明变量同时解构 let [a,b,c] [&qu…...

AXI接口的实现逻辑和底层原理,在FPGA中如何实现AXI接口,一篇文章足以搞明白!!!

AXI&#xff08;Advanced eXtensible Interface&#xff09;接口是一个点对点的接口&#xff0c;用于连接高性能的片上系统&#xff08;SoC&#xff09;中的处理器、外围设备、内存和其他IP核。以下是对AXI接口的详细解析&#xff0c;包括FPGA实现的原理、逻辑、速度以及详细的…...

《GBDT 算法的原理推导》 11-12计算损失函数的负梯度 公式解析

本文是将文章《GBDT 算法的原理推导》中的公式单独拿出来做一个详细的解析&#xff0c;便于初学者更好的理解。 公式(11-12)是GBDT算法中非常关键的一步&#xff0c;它表示了如何通过计算损失函数的负梯度来指导下一棵树的生长。 公式(11-12)如下&#xff1a; r m i − [ ∂ …...

mysql设计

大家好&#xff0c;我是捡田螺的小男孩。 昨天一位粉丝&#xff0c;咨询了一个并发的问题~ 我提供了一个乐观锁兜底的方案&#xff0c;然后发现他们的表&#xff0c;都没有加version字段的,我想到&#xff0c;这不是表设计通用字段嘛。因此&#xff0c;本文跟大家聊聊&#xf…...

Android 斗鱼面经

Android 斗鱼面经 文章目录 Android 斗鱼面经一面二面 一面 先简单描述一下JVM JRE JDK的关系 :::info JVM&#xff08;Java Virtual Machine&#xff09; Java 虚拟机。它只认识 xxx.class 这种类型的文件&#xff0c;它能够将 class 文件中的字节码指令进行识别并调用操作…...

【机器学习】26. 聚类评估方法

聚类评估方法 1. Unsupervised Measure1.1. Method 1: measure cohesion and separationSilhouette coefficient Method 2&#xff1a;Correlation between two similarity matricesMethod 3&#xff1a;Visual Inspection of similarity matrix 2. Supervised measures3. 决定…...

linux 最多能创建多少个 TCP 连接?

linux 最大允许TCP连接数 约束一&#xff1a;服务器的端口范围约束二&#xff0c;服务器文件描述符限制约束三&#xff1a;系统线程约束四&#xff1a;系统内存总结 tcp连接四元组&#xff1a;源ip&#xff0c;源端口 <> 目标ip&#xff0c;目标端口 连续对同一个目标ip及…...

我为何要用wordpress搭建一个自己的独立博客

我在csdn有一个博客&#xff0c;这个博客是之前学习编程时建立的。 博客有哪些好处呢&#xff1f; 1&#xff0c;可以写自己的遇到的问题和如何解决的步骤 2&#xff0c;心得体会&#xff0c;经验&#xff0c;和踩坑 3&#xff0c;可以转载别人的好的技术知识 4&#xff0c;宝贵…...

Linux系统每日定时备份mysql数据

一、创建存储脚本的文件夹 创建文件夹&#xff0c;我的脚本放在/root/dbback/mysql mkdir ... cd /root/dbback/mysql 二、编写脚本 vi backup_mysql.sh 复制脚本内容 DB_USER"填写用户名" DB_PASSWORD"填写密码" DB_NAME"数据库名称" # …...

书生大模型第一关Linux基础知识

任务一&#xff1a;完成SSH连接与端口映射并运行hello_world.py 1.SSH及其端口映射 2.在VSCode中安装插件&#xff1a; 3.创建开发机 最后点击创建&#xff0c;然后可能需要等待一段较长的时间&#xff0c;大概需要5分钟左右&#xff0c;如果需要排队则更长时间 然后选择…...

机器学习之fetch_olivetti_faces人脸识别--基于Python实现

fetch_olivetti_faces 数据集下载 fetch_olivetti_faceshttps://github.com/jikechao/olivettifaces sklearn.datasets.fetch_olivetti_faces(*, data_homeNone, shuffleFalse, random_state0, download_if_missingTrue, return_X_yFalse, n_retries3, delay1.0)[source] L…...

【系统设计】深入理解HTTP缓存机制:从Read-Through缓存到HTTP缓存的交互流程

在现代Web开发中&#xff0c;缓存机制扮演着至关重要的角色。它不仅提升了用户体验&#xff0c;还极大地优化了资源的使用效率。在这篇博文中&#xff0c;我们将从“Read-Through”缓存的概念出发&#xff0c;深入探讨HTTP缓存的工作原理和交互流程&#xff0c;并详细描述max-a…...

FLINK单机版安装部署入门-1

文章目录 FLINK单机版安装部署高于1.9.3需要修改配置文件flink-conf.yaml(低于1.9.3可以跳过)linux启动集群windows下启动Flink实例运行(单机)还有一种方式是上传任务包运行examples\streamingjava: Compilation failed: internal java compiler error高版本启动脚本 FLINK单机…...

深度学习-学习率调整策略

在深度学习中&#xff0c;学习率调整策略&#xff08;Learning Rate Scheduling&#xff09;用于在训练过程中动态调整学习率&#xff0c;以实现更快的收敛和更好的模型性能。选择合适的学习率策略可以避免模型陷入局部最优、震荡不稳定等问题。下面介绍一些常见的学习率调整策…...

【学员提问bug】小程序在onUnload里面调接口,用来记录退出的时间, 但是接口调用还没成功, 页面就关闭了。如何让接口在onUnload关闭前调用成功?

这种问题比较通用&#xff0c;并不涉及到具体方法执行障碍&#xff0c;所以&#xff0c;解决起来也不麻烦。但是新手往往不知道如何做。 在小程序中&#xff0c;如果在 onUnload 中调用 API 记录页面退出时间&#xff0c;但因为页面关闭速度较快导致请求未完成&#xff0c;可以…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...