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

策略模式Spring框架下开发实例

策略类Spring框架下开发实例

先列出策略模式下需要那些类:

策略接口 (Strategy),定义所有策略类必须遵循的行为。

具体策略类(如 ConcreteStrategyAConcreteStrategyB),实现不同的算法或行为。

上下文类 (Context),持有策略实例并根据条件动态选择和创建策略。

辅助类和注解(作为工具辅助构建类工厂,可忽略),为策略模式的实现提供额外的功能或配置。

具体实现

定义策略接口

采用策略模式的情况一般是封装多重if-else/switch下的不同处理逻辑,这些逻辑可以抽象为一个行为(比如封装参数,做前置校验等),将这个行为定义为接口方法

/*** 策略接口*/
public interface ProductTypeHandler {//本例中根据不同产品类型执行不同的返回参数封装逻辑void assemble(ResponseBO resBO);
}

定义策略类及其处理逻辑

将上文提到的多重if-else/switch中不同情况及其处理逻辑抽象成具体策略类和其内部方法执行逻辑


/*** 记录器参数处理类*/
@Component
//注解使用见3
@ProductTypeAssembleTag(TAG = EnumProductType.PROCESS_RECORDER)
public class RecorderHandler implements ProductTypeHandler {@Autowiredprivate RecorderService service;@Overridepublic void assemble(ResponseBO resBO) {//记录器的处理逻辑int bindDeviceNums = service.getNumByUserId(ContextUtil.getUserId());resBO.setValue(bindDeviceNums);}
}
@Component
@ProductTypeAssembleTag(TAG = EnumProductType.COMMANDER)
//继承见4
public class CommanderHandler  extends CommonHandler implements ProductTypeHandler {@Overridepublic void assemble(ResponseBO resBO) {//控制器的处理逻辑...}
}

这里用到的注解和继承可以先忽视,3,4中会做解释

Context上下文类

这个类的核心就是存储map所有的策略类,然后提供getHandler()方法,供外界匹配获取对应策略类执行相关逻辑

那么这个map是如何存储的呢?我在实践中遇到是通过Map<TypeEnum,Handler>也就是定义枚举类作为键,存储其对应枚举类

此处有一个可拓展的点就是这个map是如何封装的,我遇到的有这么两种:

  1. 在Context中将所有策略类定义为属性,然后@Resourse注入
  2. 通过注解的方式进行解耦

第一种自动注入+switch的方式

@Component
public class ProductTypeHandlerContext {@Resourceprivate CommonHandler commonHandler;@ResourceprivateRecorderHandler recorderHandler;//...其他策略类public ProductTypeHandler getHandler(EnumProductType emumType) {ProductTypeHandler handler = null;switch (EnumProductType) {case COMMANDER:handler = commonHandler;break;case RECORDER:handler = recorderHandler;break;default:throw new BizException("未匹配到目标类型");break;}return handler;}
}

可以看到第一种方案比较轻量级,下面来着重举例看看第二种情况:

@Component
public class HandlerContext{private static final Map<EnumProductTypeProductTypeHandler> handlerMap = new HashMap<>();@Autowiredprivate HandlerContext(List<ProductTypeHandler> handlers) {handlers.forEach(processor -> {//这一段是通过反射获取到策略类long count = new ArrayList<>(Arrays.asList(processor.getClass().getInterfaces())).stream().filter(m -> m.getName().equals("org.springframework.aop.framework.Advised")).count();try {Class<?> ifaceClass = (Class) (count > 0 ? processor.getClass().getMethod("getTargetClass").invoke(processor) : processor.getClass());this.handlerMap.put(ifaceClass.getAnnotation(ProductTypeAssembleTag.class).TAG(), processor);} catch (Exception e) {log.error("HandlerContext初始化失败",e);throw new BizException("HandlerContext初始化失败");}});}public ProductTypeHandler getHandler(EnumProductType emumType) {return handlerMap.get(emumType);}
}

可以看到Context主要分为三部分:

  1. map
  2. 构造函数–>初始化map
  3. getHandler()

这里的重点在2中的HandlerContext()构造方法,通过@Autowired注解,Spring会将所有继承了策略接口ProductTypeHandler的策略类注入为列表作为参数,那么在方法内部对列表中的策略类依次进行map.put就可以了

那如何将策略类对应到其所属的EnumType上呢?这里通过自定义一个注解,为其添加一个名为Tag的EnumType属性,在每个策略类上面加上这个注解,就大功告成了,这也是上面的策略类的注解来源

/*** 注解*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProductTypeAssembleTag {EnumsLogin.EnumProductType TAG();
}

至于HandlerContext()中的try中所涉及的逻辑,是检查当前的 processor 类是否是一个 Spring AOP 代理类:

"org.springframework.aop.framework.Advised"接口是 Spring AOP 代理类的标志。如果 count > 0,说明 processor 是一个 AOP 代理类。

如果 processor 是 AOP 代理类,则调用 processor.getClass().getMethod("getTargetClass").invoke(processor) 获取目标类的 Class 对象,这样可以获取到代理类的实际目标类(即被代理的类)。如果 processor 不是代理类,则直接使用 processor.getClass()

getTargetClass() 方法是 AOP 代理类的一个方法,它返回代理对象的实际目标类(即未被代理的原始类)。

进一步思考

如果策略类a,b的执行逻辑是一样的,那么要写重复的代码吗?

这时候就可以回归到最基础的继承上,通过定义一个CommonHandler,在其中写一次默认逻辑,然后其他策略类进行继承这也是上面的策略类有继承的原因

public class CommonHandler {public void assemble(ResponseBO resBO) {log.info("默认处理--目前没有特殊处理逻辑");}
}

至此,一个通过注解和继承优化的策略类实现方案就得以使用,在调用类通过注入HandlerContext,调用getHandler(enumType).assemble就可以传入枚举类获取对应策略类执行对应逻辑

总结

针对Context中map的两种初始化方案:

方案优点缺点
自动注入+switch- 简单直观,易于理解和维护
- 性能较好,避免了反射开销
- 扩展性差,需要修改 switch 语句才能添加新策略
- 高耦合,修改策略类需要修改 Context
注解解耦- 解耦性强,符合开闭原则
- 易于扩展,不需要修改现有代码
- 支持 AOP 代理
- 性能开销较高,使用了反射
– 启动时的反射性能开销

相关文章:

策略模式Spring框架下开发实例

策略类Spring框架下开发实例 先列出策略模式下需要那些类: 策略接口 (Strategy)&#xff0c;定义所有策略类必须遵循的行为。 具体策略类&#xff08;如 ConcreteStrategyA、ConcreteStrategyB&#xff09;&#xff0c;实现不同的算法或行为。 上下文类 (Context)&#xff0c;…...

DeepSeek模型量化

技术背景 大语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;&#xff0c;可以通过量化&#xff08;Quantization&#xff09;操作来节约内存/显存的使用&#xff0c;并且降低了通讯开销&#xff0c;进而达到加速模型推理的效果。常见的就是把Float16的浮…...

【练习】【回溯:组合:不同集合】力扣 17. 电话号码的字母组合

题目 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “2…...

分布式文件系统HDFS

一、HDFS简介 HDFS&#xff08; Hadoop Distributed File System &#xff09;&#xff0c;意为&#xff1a;Hadoop分布式文件系统。是Apache Hadoop核心组件之一&#xff0c;作为大数据生态圈最底层的分布式存储服务而存在。分布式文件系统解决大数据如何存储问题。分布式意味…...

从WebRTC到EasyRTC:嵌入式适配的视频通话SDK实现低延迟、高稳定性音视频通信

WebRTC最初是为浏览器之间的实时通信设计的&#xff0c;其资源需求和复杂性可能对嵌入式设备的性能提出较高要求&#xff0c;因此在嵌入式系统中应用时面临一些挑战&#xff1a; 1&#xff09;资源消耗较高 CPU和内存占用&#xff1a;WebRTC是一个功能强大的实时通信框架&…...

WordPress自定义排序插件:Simple Custom Post Order完全指南(SEO优化版)

在WordPress建站中&#xff0c;文章、分类目录或页面的默认排序方式往往无法满足个性化需求。WordPress自定义排序插件&#xff1a;Simple Custom Post Order插件&#xff0c;你可以轻松实现拖拽式自定义排序&#xff0c;无需修改代码即可优化内容展示逻辑。本文将详细介绍这款…...

docker安装ros2 并在windows中显示docker内ubuntu系统窗口并且vscode编程

这里包括docker desktop安装ros2 humble hawkshill , 安装xserver(用来在windows中显示ubuntu中窗口), vscode安装插件连接docker并配置python的一系列方法 1.安装xserver 为了能方便的在windows中显示ubuntu内的窗口,比如rqt窗口 参考文章:https://www.cnblogs.com/larva-zhh…...

【QT中的一些高级数据结构,持续更新中...】

QT中有一些很精妙、便捷的设计&#xff0c;在了解这些数据的同时&#xff0c;我们可以学到如何更好的设计代码。本贴持续更新中&#xff0c;欢迎关注和收藏 一 QScopedPointer主要特点&#xff1a;示例代码 二 Q_DISABLE_COPY 一 QScopedPointer QScopedPointer 是 Qt 中的一种…...

简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用

简单工厂模式&#xff08;Simple Factory Pattern&#xff09;虽然不属于 GoF 23 种经典设计模式&#xff0c;但在实际开发中非常常用&#xff0c;尤其是在 Spring Boot 项目中。它提供了一种简单的方式来创建对象&#xff0c;将对象的创建逻辑集中到一个工厂类中。 一、简单工…...

《95015网络安全应急响应分析报告(2024)》

2025年2月&#xff0c;95015服务平台发布了最新一期的《95015网络安全应急响应分析报告&#xff08;2024&#xff09;》。报告分别从整体形势、受害者特征、攻击者特征等方面&#xff0c;对2024年95015平台接报的739起网络安全应急响应事件展开分析&#xff0c;并给出了7个年度…...

TensorFlow v2.16 Overview

TensorFlow v2.16 Overview 一、模块 Modules二、类 Classes三、函数 Functions TensorFlow v2.16.1 Overview 一、模块 Modules 模块是TensorFlow中组织代码的一种方式&#xff0c;将相关的功能和类封装在一起&#xff0c;方便用户使用和管理。每个模块都提供了特定领域的公共…...

Udp发送和接收数据(python和QT)

服务端代码 (python) import socketdef udp_server(host0.0.0.0, port12345):# 创建一个UDP套接字sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定服务器的IP地址和端口号sock.bind((host, port))print(f"UDP服务器已启动&#xff0c;监听端口 {port}...&…...

element-plus 根据条件显示多选框

代码如下&#xff1a; <el-table :data"pager.lists" selection-change"handleSelectionChange" row-key"id" :tree-props"{ checkStrictly: true }" :cell-class-name"cellClass"> <el-table-column type"s…...

Ubuntu 22.04 Install deepseek

前言 deepseekAI助手。它具有聊天机器人功能&#xff0c;可以与用户进行自然语言交互&#xff0c;回答问题、提供建议和帮助解决问题。DeepSeek 的特点包括&#xff1a; 强大的语言理解能力&#xff1a;能够理解和生成自然语言&#xff0c;与用户进行流畅的对话。多领域知识&…...

DeepSeek赋能智慧文旅:新一代解决方案,重构文旅发展的底层逻辑

DeepSeek作为一款前沿的人工智能大模型&#xff0c;凭借其强大的多模态理解、知识推理和内容生成能力&#xff0c;正在重构文旅产业的发展逻辑&#xff0c;推动行业从传统的经验驱动向数据驱动、从人力密集型向智能协同型转变。 一、智能服务重构&#xff1a;打造全域感知的智…...

小程序的分包

1.分包的概念以及基本用法 2.在小程序项目里面添加自己的分包 3.给分包加上别名 4.查看分包体积大小 5.分包的打包原则 6.分包的引用原则 7.独立分包 8.分包的预下载...

RTSP场景下RTP协议详解及音视频打包全流程

RTSP场景下RTP协议详解及音视频打包全流程 一、RTSP与RTP的关系 RTSP&#xff1a;负责媒体会话控制&#xff08;DESCRIBE、SETUP、PLAY、PAUSE&#xff09;&#xff0c;通过SDP协商传输参数&#xff08;端口、编码格式、封装模式&#xff09;。RTP&#xff1a;实际传输音视频数…...

使用API有效率地管理Dynadot域名,为域名部署DNS安全拓展(DNSSEC)

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…...

如何基于transformers库通过训练Qwen/DeepSeek模型的传统分类能力实现文本分类任务

文章目录 模型与环境准备文档分析源码解读模型训练及推理方式进阶:CPU与显存的切换进阶:多卡数据并行训练🔑 DDP 训练过程核心步骤🚫 DDP 不适用于模型并行⚖️ DDP vs. Model Parallelism⚙️ 解决大模型训练的推荐方法🎉进入大模型应用与实战专栏 | 🚀查看更多专栏…...

开源一款I2C电机驱动扩展板-FreakStudio多米诺系列

总线直流电机扩展板 原文链接&#xff1a; FreakStudio的博客 摘要 设计了一个I2C电机驱动板&#xff0c;通过I2C接口控制多个电机的转速和方向&#xff0c;支持刹车和减速功能。可连接16个扩展板&#xff0c;具有PWM输出、过流过热保护和可更换电机驱动芯片。支持按键控制…...

终极静音方案:5分钟掌握FanControl风扇控制软件完全指南

终极静音方案&#xff1a;5分钟掌握FanControl风扇控制软件完全指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/…...

RISC-V IDE混战,我为什么最终选择了Segger Embedded Studio?

RISC-V IDE选型实战&#xff1a;为何Segger Embedded Studio成为我的最终选择&#xff1f; 当兆易创新GD32V103开发板静静躺在桌面上时&#xff0c;我意识到这个预算有限的物联网网关项目正面临关键抉择——在碎片化的RISC-V生态中&#xff0c;如何选择一款既符合团队技术栈又能…...

告别臃肿镜像!5分钟学会用Alpine Linux的apk命令精简你的Dockerfile

告别臃肿镜像&#xff01;5分钟学会用Alpine Linux的apk命令精简你的Dockerfile 在容器化部署的世界里&#xff0c;镜像体积往往决定着部署效率和资源利用率。每当看到那些动辄几百MB的基础镜像&#xff0c;作为追求极致的开发者&#xff0c;你是否也感到一丝不安&#xff1f;这…...

智能云架构革命:从被动响应到主动服务的Agentic Cloud

1. 智能云基础设施的范式革命当我们在2023年谈论云计算时&#xff0c;已经不再局限于虚拟机分配和存储扩容这些基础概念。最近半年&#xff0c;我参与设计的一个新型云平台项目让我深刻意识到&#xff1a;云基础设施正在经历从"被动响应"到"主动服务"的质变…...

【技术解析】Informer:突破Transformer瓶颈,重塑长时序预测的深度学习新范式

1. 长时序预测的挑战与Transformer的瓶颈 想象一下你正在处理电力负荷预测任务&#xff0c;需要根据过去三年的用电记录预测未来一个月的需求。传统方法可能直接截取最近几周数据来训练模型&#xff0c;但这样会丢失季节性、节假日等长期规律。Transformer模型原本是处理这类长…...

从零开始玩转ZU19EG评估板:手把手教你搭建第一个ZYNQ MPSoC原型系统(含资源分配避坑指南)

从零开始玩转ZU19EG评估板&#xff1a;手把手教你搭建第一个ZYNQ MPSoC原型系统 第一次拿到ZU19EG评估板时&#xff0c;我被它强大的硬件配置震撼到了——四核Cortex-A53处理器、双核Cortex-R5实时处理器、114万逻辑单元的可编程逻辑&#xff0c;还有16GB的DDR4内存。但随之而来…...

面向高端车载环境的DCDC转换器MOSFET选型策略与器件适配手册

随着汽车电气化与智能化进程加速&#xff0c;车载电源系统正向高电压、高功率密度及高可靠性方向演进。DCDC转换器作为整车电能分配与电压转换的核心&#xff0c;其性能直接关系到车载电子设备的稳定运行与整车能效。功率MOSFET作为转换器中的关键开关元件&#xff0c;其选型直…...

蓝光媒体深度解析:BDInfo技术原理与实战应用

蓝光媒体深度解析&#xff1a;BDInfo技术原理与实战应用 【免费下载链接】BDInfo BDInfo from http://www.cinemasquid.com/blu-ray/tools/bdinfo 项目地址: https://gitcode.com/gh_mirrors/bd/BDInfo 在蓝光媒体处理领域&#xff0c;专业的技术分析工具对于理解复杂的…...

Harness Engineering:AI Agent 落地企业的工程化核心

2025年是AI Agent的爆发元年&#xff0c;各类智能体工具层出不穷&#xff0c;但落地企业生产环境时却问题频发——越权操作、逻辑混乱、无法审计的情况屡见不鲜。2026年&#xff0c;Harness Engineering 成为行业破局关键&#xff0c;它让AI Agent从「实验室玩具」变成「企业级…...

抖音下载器终极实战指南:高效批量下载无水印视频与直播回放

抖音下载器终极实战指南&#xff1a;高效批量下载无水印视频与直播回放 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback …...