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

SpringBoot 多实现类实战:告别 if-else,拥抱策略模式

在 SpringBoot 开发中一个接口对应多个实现类是极其常见的场景例如支付方式微信、支付宝、银联、通知渠道短信、邮件、钉钉或登录策略密码、验证码、第三方。如果处理不当代码中会充斥着大量的if-else判断导致代码臃肿、难以维护。本文将带你从基础到进阶详细拆解 SpringBoot 处理多实现类的最佳实践并重点介绍结合​​策略模式​​与​​工厂模式​​的优雅解法。一、 问题引入为什么直接注入会报错假设我们有一个通知服务接口NotificationService它有两个实现类短信通知和邮件通知。public interface NotificationService { void send(String recipient, String content); } Service public class SmsNotificationService implements NotificationService { Override public void send(String phone, String content) { System.out.println(给手机【%s】发送内容:%s.formatted(phone, content)); } } Service public class EmailNotificationService implements NotificationService { Override public void send(String email, String content) { System.out.println(给邮箱【%s】发送内容:%s.formatted(email, content)); } }如果你在 Controller 中直接使用Autowired注入接口Spring 容器会抛出NoUniqueBeanDefinitionException异常RestController public class TestController { Autowired private NotificationService notificationService; // 报错期望单个匹配但找到 2 个 }这是因为 Spring 的依赖注入机制在默认情况下要求 Bean 是唯一的。当发现多个候选 Bean 时它不知道应该注入哪一个。接下来我们将介绍几种解决方案。二、 基础解决方案注解控制1. 使用 Primary 设置默认实现​​适用场景​​存在一个最常用的默认实现其他实现仅在特定场景下使用。​​实现方式​​在默认实现类上添加Primary注解。Service Primary // 标记为首选实现 public class SmsNotificationService implements NotificationService { // ... 实现逻辑 }​​效果​​当直接注入NotificationService时Spring 会优先选择带有Primary注解的 Bean。如果你需要注入其他实现则必须配合Qualifier注解指定。2. 使用 Qualifier 精确点名​​适用场景​​需要明确指定使用哪个实现类。​​实现方式​​在注入点使用Qualifier注解并传入实现类的 Bean 名称默认是类名首字母小写。RestController public class TestController { Autowired Qualifier(emailNotificationService) // 指定注入邮件服务 private NotificationService notificationService; }​​进阶用法​​自定义Qualifier注解使代码更具语义化。Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) Retention(RetentionPolicy.RUNTIME) Qualifier(email) // 继承 Qualifier public interface Email {} Service Email // 使用自定义注解标记 public class EmailNotificationService implements NotificationService { // ... }3. 使用 Resource 按名称注入​​适用场景​​习惯使用 JSR-250 标准注解或需要根据变量名自动匹配。​​实现方式​​使用Resource注解它默认按名称byName进行注入。RestController public class TestController { Resource // 默认按变量名 emailService 查找 Bean private NotificationService emailService; }​​注意​​Resource的匹配规则是先按名称找找不到再按类型找。如果变量名与 Bean 名称不匹配可能会导致注入失败。三、 进阶实战策略模式 工厂模式推荐上述注解方案虽然解决了注入问题但在业务逻辑中我们通常需要根据​​运行时参数​​如用户选择的支付方式来动态调用不同的实现。如果使用if-else硬编码代码会非常丑陋且难以扩展。此时​​策略模式​​ 是最佳选择。1. 核心思想​​策略模式​​将每种算法如支付、登录封装成独立的类实现统一的接口。调用者无需关心具体实现只需调用接口方法。​​工厂模式​​创建一个工厂类负责根据传入的标识如 wechat创建并返回对应的策略对象。2. 实战案例多端登录系统假设我们要实现一个支持​​账号密码登录​​、​​微信扫码登录​​和​​手机验证码登录​​的系统。步骤 1定义策略接口首先定义一个统一的登录策略接口所有登录方式都必须实现该接口。public interface LoginStrategy { /** * 获取登录类型标识 * return 如 password, wechat, sms */ String getLoginType(); /** * 执行登录逻辑 * param params 登录参数Map 或自定义 DTO * return 登录结果 */ String execute(MapString, String params); }步骤 2实现具体策略为每种登录方式创建一个实现类并使用Service或Component注解将其注册为 Spring Bean。​​账号密码登录策略​​Service public class PasswordLoginStrategy implements LoginStrategy { Override public String getLoginType() { return password; } Override public String execute(MapString, String params) { String username params.get(username); String password params.get(password); // 1. 校验密码实际应从数据库查询并解密 if (!123456.equals(password)) { throw new IllegalArgumentException(密码错误); } // 2. 检查账号是否锁定等业务逻辑 checkUserLocked(username); return 登录成功(用户名密码); } private void checkUserLocked(String username) { // 调用用户服务检查账号状态 System.out.println(检查用户 username 是否锁定); } }​​微信扫码登录策略​​Service public class WechatLoginStrategy implements LoginStrategy { Override public String getLoginType() { return wechat; } Override public String execute(MapString, String params) { String authCode params.get(authCode); // 1. 调用微信接口获取用户信息 String openId callWechatApi(authCode); // 2. 根据 openId 查询用户绑定关系 String userId getUserIdByOpenId(openId); if (userId null) { throw new IllegalArgumentException(微信账号未绑定系统用户); } return 登录成功(微信扫码); } private String callWechatApi(String authCode) { // 实际应调用微信开放平台 API System.out.println(调用微信接口, authCode authCode); return wechat_open_id_123; } }步骤 3构建策略工厂核心这是整个模式的核心。工厂类负责收集所有的策略 Bean并根据类型返回对应的策略实例。Component public class LoginStrategyFactory { // Spring 会自动将所有 LoginStrategy 的实现类注入到这个 Map 中 // Key: Bean 的名称 (默认是类名首字母小写如 passwordLoginStrategy) // Value: 具体的策略实例 private final MapString, LoginStrategy strategyMap; // 构造器注入推荐 public LoginStrategyFactory(MapString, LoginStrategy strategyMap) { this.strategyMap strategyMap; } /** * 根据登录类型获取对应的策略 * param loginType 登录类型标识 * return 策略实例 */ public LoginStrategy getStrategy(String loginType) { // 遍历 Map找到类型匹配的策略 for (LoginStrategy strategy : strategyMap.values()) { if (loginType.equals(strategy.getLoginType())) { return strategy; } } throw new RuntimeException(未找到对应的登录策略: loginType); } }​​技术原理​​Spring 框架支持将某个接口的所有实现类自动注入到一个MapString, T或ListT中。Map的 Key 默认是 Bean 的名称可通过Service(自定义名称)修改Value 是 Bean 实例。这为我们实现策略工厂提供了极大的便利。步骤 4在 Controller 中调用在 Controller 中我们不再需要写if-else只需注入工厂传入类型参数即可。RestController RequestMapping(/api) public class LoginController { Autowired private LoginStrategyFactory strategyFactory; PostMapping(/login) public String login(RequestParam String type, RequestBody MapString, String params) { // 1. 通过工厂获取策略无需 if-else 判断 LoginStrategy strategy strategyFactory.getStrategy(type); // 2. 执行策略 String result strategy.execute(params); return result; } }3. 方案优势​​符合开闭原则​​当需要新增一种登录方式如支付宝登录时你只需要新增一个实现类如AlipayLoginStrategy实现LoginStrategy接口即可。​​无需修改工厂和 Controller 的任何代码​​。​​代码解耦​​每种登录逻辑独立成类职责单一便于单元测试和维护。​​消除硬编码​​彻底告别了冗长的if-else或switch-case语句。四、 总结与最佳实践方案适用场景优点缺点​​Primary​​有明确的默认实现配置简单无法动态切换灵活性差​​Qualifier​​实现类少且固定精确控制注入目标硬编码扩展性差​​策略模式​​​​业务复杂需动态扩展​​​​高扩展性代码优雅​​代码结构稍复杂需要设计工厂​​实战建议​​对于简单的配置切换如开发环境用 Mock 服务生产环境用真实服务使用Primary或ConditionalOnProperty即可。对于核心业务逻辑如支付、登录、通知​​强烈推荐使用策略模式​​。虽然前期设计成本稍高但随着业务迭代其维护成本远低于传统的if-else写法。通过本教程你已经掌握了 SpringBoot 处理多实现类的多种姿势。在实际项目中请根据业务复杂度灵活选择让代码既跑得快又写得好。

相关文章:

SpringBoot 多实现类实战:告别 if-else,拥抱策略模式

在 SpringBoot 开发中,一个接口对应多个实现类是极其常见的场景,例如支付方式(微信、支付宝、银联)、通知渠道(短信、邮件、钉钉)或登录策略(密码、验证码、第三方)。如果处理不当&a…...

公务员暂停工伤保险

登录进入办理页面 暂停工伤保险适合调出、退休人员上传附件点击提交 退休选择工伤养老保险基数 公积金医疗保险基数...

着色器multi_compile笔记

概述一句multi_compile后面写若干个关键字XXX,在代码里用#if XXX条件编译一段代码。开启、关闭关键字关键字的开启关闭在材质debug界面。在Valid Keywords填的关键字如果在某句multi_compile里会自动进入Valid Keywords,否则进入Invalid。代码开启关键字…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》007-拍摄基础:参数设置与镜头语言解析(景别与镜头运动)

💎【行业认证权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》006-拍摄基础:参数设置与镜头语言解析(短视频的参数设置)

💎【行业认证权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

Python爬虫实战:监听前端网络流,aiohttp 极速并发抓取淘宝直播排行榜!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐ 🉐福利: 一次订阅后,专栏内的所有文章可永…...

Python爬虫实战:构建 DeviantArt 每日精选艺术作品的增量采集流水线!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐ 🉐福利: 一次订阅后,专栏内的所有文章可永…...

基于C#的工业机器人上位机控制程序开发(搭配松下PLC + MC协议)

以下是为《基于C#的工业机器人上位机控制程序开发(搭配松下PLC MC协议)》这篇文章补充的更多实用代码示例,覆盖工业现场最常遇到的功能模块。这些代码基于 .NET 8/9 自封装 MC 协议客户端,2026年主流工业做法。 1. 完整的心跳 …...

好玩又实用:C#上位机 + YOLO 实现宠物行为识别系统

好玩又实用:C#上位机 YOLO 实现宠物行为识别系统 作为一名资深铲屎官,我曾一度被这些问题困扰: 出门上班时,猫咪是在乖乖睡觉还是在疯狂拆家?狗狗是不是又在啃咬家具?想知道宠物的日常行为,却只…...

玩转Docker | 使用Docker部署PDF工具箱BentoPDF

玩转Docker | 使用Docker部署PDF工具箱BentoPDF 前言 一、BentoPDF项目介绍 BentoPDF简介 BentoPDF主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署BentoPDF服务 下载BentoPDFr镜像 创建BentoPDF容器 检查容器状态 检查BentoPDF服务端口 安…...

C程序中隐藏的数据溢出陷阱

C程序中隐藏的数据溢出陷阱 通常的规则: 当代码中对char、short等更短的类型进行算术运算时,编译器会自动将它们提升为int再进行计算。假设16位、32位无符号数类型,分别定义为UINT16、UNIT32一.计算过程溢出对16bit机器,如以下程序…...

第八届信息科学、电气与自动化工程国际学术会议(ISEAE 2026)

第八届信息科学、电气与自动化工程国际学术会议(ISEAE 2026) 2026 8th International Conference on Information Science, Electrical and Automation Engineering 时间地点:2026年4月17-19日 黑龙江省大庆市 会议官网:http:/…...

使用RISC-V IDE MRS2进行代码开发

MounRiver Studio Ⅱ(MRS2)使用了VSCode同款框架,继承VSCode代码编辑功能的基础上,还增加了一系列嵌入式开发辅助功能。【主题切换】MRS2内置多种深浅色界面配色主题,可通过工具栏快捷配置按钮来进行切换:【代码补全】在代码开发过…...

T32状态下寄存器组织、AArch32/64重要寄存器(ARM处理器架构模型——寄存器组织,中篇)

本文声明:内容来源于网络,进行整合/再创作;部分内容由AI辅助生成。T32状态下的寄存器组织Thumb状态寄存器是ARM状态的子集。注意,在Thumb状态下发生异常时,处理器自动进入ARM状态。A32与T32状态下的寄存器组织在Thumb状…...

问题整理清单

问题整理清单 请问模版匹配这个HHandle 这个句柄 序列化之前和序列化之后不一样呢 ?“HALCON error #2404: Invalid handle type in operator do_ocr_multi_class_cnnpython训练出来的结果预测之后的结果很对,但是一到C#上面就不行了什么是LinuxCNC...

【Dv3Admin】FastCRUD MD编辑器操作

富文本字段和 Markdown 字段在后台表单里的问题,本质上很像,真正麻烦的都不是“能不能挂进去”,而是挂进去以后尺寸、回显、校验和展示边界是否稳定。放到 md-editor-v3 之后,最常见的问题通常集中在编辑区高度不合适、宽度被表单…...

【C++】左值引用、右值引用

目录 一、右值引用的意义 二、基础:理解左值与右值 1. 左值(Lvalue,Locator Value) 常见的左值场景: 2. 右值(Rvalue,Read Value) 2.1 纯右值(prvalue)…...

Tower I3C Host Adapter 使用范例 (20)

Easyi3C是一家领先的嵌入式系统工具供应商,可简化各种通信协议的开发和调试。公司提供一系列产品,旨在帮助工程师和开发人员更高效地使用 I3C、I2C等协议。 基于Tower I3C Host Adapter 测试DDR5 RCD (4) 一 DDR5 RCD I3C背景介绍 在高性能计算和服务器…...

Qt进程间通信

QSharedMemory 共享内存(Shared Memory)是一种进程间通信(Inter-Process Communication, IPC)机制,允许多个进程共享同一块内存区域。共享内存提供了高效的数据交换方式,适用于需要频繁传递大量数据的场景。…...

Hive数仓分区设计与更新操作指南

目录 一、Hive 分区概述 1.1 分区的核心作用 1.2 分区的本质示例 二、分区设计原则 2.1 分区字段选择原则 2.2 分区粒度与数量控制 2.3 分区设计常见误区 三、分区表的创建 3.1 静态分区表 3.1.1 创建静态分区表 3.1.2 向静态分区表插入数据 3.2 动态分区表 3.2.1 …...

2026年最新免费5S管理系统盘点!盘点10个免费的5S系统!

在2026年制造业数字化转型的关键节点,寻找一套高效且低成本的5S管理系统已成为众多中小企业的迫切需求。面对市场上繁杂的软件选择,如何精准定位到真正的免费5S系统?本文为您带来2026年最新免费5S管理系统盘点,深度剖析当前市场格…...

一、STM32入门

用的是正点原子STM32F103MINI、JLINK v8 1.准备工作 1.1手册 1.1.1数据手册 STM32F103RCT6 开发板各个元件的特性。 1.1.2参考手册 在逻辑层面上,如何利用STM32F10X开发板各个部位的特性实现各种功能。 1.1.3厂家的学习开发手册 具体厂家设计的代码层面的如何学…...

《UNIX高级环境编程》第十三章 守护进程(一文读懂UNIX下守护进程)

一、守护进程的特征守护进程是一种生命周期较长的进程,常常在系统启动时被运行,在系统关闭时终止,并且没有关联的终端设备,是一个后台进程。一个系统中,父进程ID为0的一般是内核进程。进程1通常是init进程,…...

杰理AC695N/AC696N歌词回调

想要连接蓝牙播放音乐显示歌词杰理的SDK已经做好封装了, 等待我们去调用就可以了, ac695n和ac696n的sdk调用方法都一样下面开始还有一点最重要的是下面这个宏必须要打开, 最后连接蓝牙播放音乐就能在日志打印中看到歌词的回调了还有一个做法是可以把A2DP的这个宏关掉, 然后就可…...

配置中心的作用?Nacos 配置中心原理?

一句话回答:配置中心的作用,就是把分散在各个服务里的配置统一集中管理,并支持动态推送和环境隔离,避免每次改配置都去改代码、重启服务。 Nacos 官方也把自己定位成“动态配置服务”,强调配置的中心化、外部化和动态化…...

NPM Script 实战:常用命令设计与封装|Vue 工程化篇

【NPM Script】Vue 前端工程化实操:从核心封装逻辑到落地,彻底搞懂 npm run 常用命令最佳写法,避开端口占用、环境变量、多环境构建高频坑! 📑 文章目录 开篇一、NPM Script 是什么?为什么用它&#xff1f…...

KMP算法之 next 数组的计算

/*** brief 计算模式串的next数组(部分匹配表),并可视化计算过程* param pattern 模式串(待查找的基因片段)* param next 输出参数:存储next数组(长度需≥模式串长度)*/ void kmp_ge…...

发电机组并网技术研究

一、概述在现代电力供应体系中,柴发机组作为应急电源或后备电源,是应对市电中断、用电高峰负荷及特殊场景电力需求,保障电力持续、稳定供应的关键核心设备,其典型应用系统如下图1所示(图1:柴发机组典型供电…...

负载均衡策略有哪些?如何自定义?

你先记一句总纲:负载均衡策略,就是当一个服务有多个实例时,客户端或网关该按什么规则选一个实例去调用。常见负载均衡策略1. 轮询 Round Robin按顺序一个一个分配请求:第1个请求给实例A第2个请求给实例B第3个请求给实例C优点是简单…...

深度解构 BeyondMimic 引导扩散控制策略

深度解构 BeyondMimic 引导扩散控制策略 引导扩散就是先利用 Tracking 的方式训练出多个可以实现各种动作的小模型,随后利用这些小模型在仿真中生成大量的数据,用来训练出一个大模型,也就是蒸馏。但这里用的不是传统的蒸馏手段,我…...