Spring 策略模式实现

Spring 策略模式实现:工厂方法与自动注入详解

1. 背景介绍

在复杂的业务系统中,我们常常需要根据不同的场景选择不同的处理策略。本文将详细介绍在 Spring 框架中实现策略模式的两种主要方法。

2. 方案一: 手动注册工厂模式

2.1 定义工厂类

@Component
public class CalculateHandlerFactory implements InitializingBean, ApplicationContextAware {private ApplicationContext applicationContext;// 存储不同策略的映射private static final Map<String, CalculateHandler> HANDLER_MAP = new HashMap<>();// 初始化方法,自动注册所有处理器@Overridepublic void afterPropertiesSet() throws Exception {applicationContext.getBeansOfType(CalculateHandler.class).values().forEach(v -> HANDLER_MAP.putIfAbsent(v.getType(), v));}// 设置 ApplicationContext@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}// 根据类型获取对应的处理器public CalculateHandler getCalculateHandler(String calculateType) {return HANDLER_MAP.getOrDefault(calculateType, null);}
}

2.2 实现步骤

  1. 实现 InitializingBean 接口,在 Bean 初始化时自动注册处理器
  2. 实现 ApplicationContextAware 接口,获取 Spring 应用上下文
  3. 使用 Map 存储不同类型的处理器
  4. 提供根据类型获取处理器的方法

2.3 优点

  • 对注册过程有精细化控制
  • 可以添加自定义的注册逻辑
  • 灵活性高

3. 方案二: 自动注入策略模式

3.1 定义策略接口

public interface CalculateHandler {// 获取处理类型String getType();// 具体计算方法double calculate(double a, double b);
}

3.2 实现具体策略

@Component
public class AddCalculateHandler implements CalculateHandler {@Overridepublic String getType() {return "add";}@Overridepublic double calculate(double a, double b) {return a + b;}
}@Component
public class SubtractCalculateHandler implements CalculateHandler {@Overridepublic String getType() {return "subtract";}@Overridepublic double calculate(double a, double b) {return a - b;}
}

3.3 策略管理服务

@Service
public class CalculateService {@Autowiredprivate Map<String, CalculateHandler> calculateHandlerMap;public double calculate(String type, double a, double b) {CalculateHandler handler = calculateHandlerMap.get(type);if (handler == null) {throw new IllegalArgumentException("未找到对应的计算处理器");}return handler.calculate(a, b);}
}

3.4 工作原理详解

3.4.1 自动注册机制

当使用 @Autowired Map<String, Interface> 时,Spring 会:

  • 扫描所有实现指定接口的 Bean
  • 使用 Bean 名称作为 Map 的 Key
  • 使用 Bean 实例作为 Map 的 Value
3.4.2 Bean 名称规则
  • 默认使用类名首字母小写作为 Bean 名称
  • 可以通过 @Component("customName") 自定义 Bean 名称

4. 高级用法

4.1 按优先级排序

@Service
public class CalculateService {@Autowiredprivate Map<String, CalculateHandler> calculateHandlerMap;// 按照 @Order 注解排序@Autowiredprivate List<CalculateHandler> calculateHandlerList;
}

4.2 自定义 Key 获取

@Service
public class CalculateService {@Autowiredprivate Map<String, CalculateHandler> calculateHandlerMap;// 使用自定义方法获取 Keypublic double calculate(String type, double a, double b) {CalculateHandler handler = calculateHandlerMap.values().stream().filter(h -> h.getType().equals(type)).findFirst().orElseThrow(() -> new IllegalArgumentException("未找到处理器"));return handler.calculate(a, b);}
}

5. 两种方案对比

特性手动注册自动注入
代码复杂度较高较低
灵活性
初始化控制精细简单
性能略低略高

6. 优点和适用场景

6.1 优点

  1. 代码解耦
  2. 动态扩展
  3. 无需手动维护注册表
  4. 充分利用 Spring 依赖注入机制

6.2 适用场景

  • 策略模式
  • 插件化开发
  • 可插拔的业务处理器
  • 系统扩展性要求高的场景

7. 注意事项

  1. 保证 Bean 名称唯一性
  2. 接口设计要合理
  3. 做好异常处理
  4. 考虑性能和扩展性

8. 最佳实践

  1. 保持接口简洁明了
  2. 明确定义每个策略的职责
  3. 合理设计方法签名
  4. 添加必要的异常处理
  5. 考虑性能和扩展性

结论

通过 Spring 的依赖注入和自动装配机制,我们可以非常优雅地实现策略模式,使代码更加灵活、可读和可维护。选择合适的实现方式,需要根据具体的业务场景和系统架构来权衡。

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

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

相关文章

机器学习——线性回归(LinearRegression)

Python 线性回归详解&#xff1a;从原理到实战线性回归&#xff08;Linear Regression&#xff09;是机器学习中最基础也是最重要的算法之一&#xff0c;广泛应用于预测分析领域&#xff0c;例如房价预测、销售额预测等。本文将带你从理论出发&#xff0c;用 Python 手把手实现…

H.264视频的RTP有效载荷格式(翻译自:RFC6184 第5节 RTP有效载荷格式)

RTP协议格式 RFC地址&#xff1a;https://datatracker.ietf.org/doc/html/rfc6184 RTP报头的格式在RFC3550中指定 0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1------------------------…

秒级构建消息驱动架构:描述事件流程,生成 Spring Cloud Stream+RabbitMQ 代码

在消息驱动架构开发中&#xff0c;Spring Cloud Stream 与 RabbitMQ 的整合往往需要手动配置绑定器、定义消息通道、编写消费逻辑&#xff0c;流程繁琐且易出错。而飞算JavaAI 作为高效的 IDE 插件&#xff0c;能让开发者通过自然语言描述事件流程&#xff0c;自动生成可运行的…

从零搭建3D激光slam框架-基于mid360雷达节点实现

目录 MID360雷达介绍 雷达SDK编译与测试 雷达驱动的修改、编译与测试 去ros的编译方式 livox_ros_driver2的代码框架介绍 livox_ros_driver2编译 雷达IP配置文件介绍 常见问题介绍 优化改进 MID360雷达介绍 1 硬件介绍&#xff1a; livox-mid360是大疆的一款非重复扫描…

【Spring】日志级别的分类和使用

文章目录介绍日志级别的分类日志级别的顺序日志级别的使用介绍 日志级别代表着日志信息对应问题的严重性&#xff0c;为了更快的筛选符合目标的日志信息 试想一下这样的场景&#xff0c;假设你是一家 2 万人公司的老板&#xff0c;如果每个员工的日常工作和琐碎的信息都要反馈…

【C++】第十九节—一文万字详解 | AVL树实现

好久不见&#xff0c;我是云边有个稻草人&#xff0c;偶尔中二博主与你分享C领域专业知识^(*&#xffe3;(oo)&#xffe3;)^ 《C》—本篇文章所属专栏—持续更新中—欢迎订阅~喔 目录 一、AVL的概念 二、AVL树的实现 2.1 AVL树的结构 2.2 AVL树的插入 【AVL树插入⼀个值…

【Delphi】快速理解泛型(Generics)

Delphi的泛型&#xff08;generics&#xff09;是一项强大的特性&#xff0c;它使得代码更加灵活、类型安全&#xff0c;并且可以实现各种通用的数据结构和算法。下面我将为你详细介绍Delphi中的泛型&#xff0c;包括基本概念、语法、常用实例&#xff0c;以及使用建议。Delphi…

Java Stream流的使用

获取Stream流 单列集合直接使用stream()方法 List<String> list Arrays.asList("a", "b", "c"); Stream<String> stream list.stream(); // 获取顺序流数组使用静态方法Arrays.stream() String[] array {"a", "b&…

前端实现添加水印,两种方式

一、自定义指令的方式/*需求&#xff1a;给整个页面添加背景水印。思路&#xff1a;1、使用 canvas 特性生成 base64 格式的图片文件&#xff0c;设置其字体大小&#xff0c;颜色等。2、将其设置为背景图片&#xff0c;从而实现页面或组件水印效果使用&#xff1a;设置水印文案…

使用LangChain构建法庭预定智能体:结合vLLM部署的Qwen3-32B模型

文章目录 技术架构概述 核心实现步骤 1. 配置vLLM与Qwen3-32B模型 2. 定义工具(Tools) 3. 构建Agent系统 4. 运行与交互 关键技术亮点 1. 工具调用自动化 2. Hermes解析器优势 3. 对话记忆管理 实际运行效果 性能优化建议 扩展应用场景 总结 在人工智能应用开发中,如何让大语…

vscode开发微信小程序

下载插件 插件下载位置 1.微信小程序开发工具 2.vscode weapp api 3.vscode wxml 4.vscode-wechat 创建项目 终端运行命令 cd 到要创建项目的目录执行命令&#xff1a;vue create -p dcloudio/uni-preset-vue test test就是项目名称 选择默认模板&#xff0c;回车 出现下图这…

板凳-------Mysql cookbook学习 (十二--------3_3)

https://cloud.tencent.com/developer/article/1454690 侯哥的Python分享 # 创建节点 class Node(object):def __init__(self,item):self.element itemself.next None# 创建单链表类 class SingleLinkList(object):def __init__(self):self.header Noneself.length 0# 1、判…

Flutter开发实战之CI/CD与发布流程

第12章:CI/CD与发布流程 在前面的章节中,我们学习了Flutter应用开发的各个方面,从基础UI构建到复杂的状态管理,从网络请求到本地存储。现在,我们将探讨一个同样重要但常被忽视的话题:如何将我们精心开发的应用高效、可靠地发布到各大应用商店。 想象一下,你花费了数月…

ElasticSearch 的3种数据迁移方案

在实际工作中&#xff0c;我们经常会遇到需要将自建的 Elasticsearch 迁移上云&#xff0c;或者迁移到其他 ES 集群的情况。这时&#xff0c;选择合适的数据迁移方案就显得尤为重要啦。今天就来给大家介绍三种常用的迁移方案&#xff0c;分别是 COS 快照、logstash 和 elastics…

MySQL 中的“双路排序”与“单路排序”:原理、判别与实战调优

一句话导读 ORDER BY 不能走索引时&#xff0c;MySQL 会在 Server 层做一次 filesort。内部实现分 单路&#xff08;全字段&#xff09; 与 双路&#xff08;rowid&#xff09; 两种&#xff1b;了解它们的触发条件、判别方法与调优思路&#xff0c;是 SQL 性能优化的必修课。一…

OpenLayers 综合案例-信息窗体-弹窗

看过的知识不等于学会。唯有用心总结、系统记录&#xff0c;并通过温故知新反复实践&#xff0c;才能真正掌握一二 作为一名摸爬滚打三年的前端开发&#xff0c;开源社区给了我饭碗&#xff0c;我也将所学的知识体系回馈给大家&#xff0c;助你少走弯路&#xff01; OpenLayers…

GaussDB 开发基本规范

1 集中式1.1数据库价值特性推荐特性分类特性列表说明表类型PARTITION表数据分区存储引擎行存储按行顺序存储表&#xff0c;建议点查&#xff0c;增删改操作较多场景下使用事务事务块显式启动事务单语句事务不显式启动事务&#xff0c;单语句即为事务扩容在线扩容扩节点和数据重…

工作中使用git可能遇到的场景

1.main历史发布版本出问题需要查看&#xff0c;怎么切换历史发布版本&#xff1f;git reset --hard commitid 更新本地库和代码2.A分支的代码已经做过一些功能&#xff0c;想迁移到B分支当前在A分支git checkout B &#xff08;切换到B分支&#xff09;git cherry-pick A的com…

【Spring AI】本地大型语言模型工具-Ollama

Ollama 是一个专注于在本地运行大型语言模型&#xff08;LLM&#xff09;的工具&#xff0c;支持多种开源模型&#xff08;如 Llama 3、Mistral、Gemma 等&#xff09;&#xff0c;提供简单的命令行和 API 接口。<dependency><groupId>org.springframework.ai</…

电机S加减速

STM32步进电机S型加减速算法_stm32___build__-2048 AI社区 以上&#xff0c;电机加减速说的非常清楚&#xff0c;收藏点赞&#xff01;