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

Spring Boot + 策略模式:增强接口扩展性的最佳实践

一、为什么需要策略模式在实际业务开发中经常会遇到一个接口有多种不同实现方式的场景。例如支付系统微信支付、支付宝支付、银行卡支付订单折扣满减、打折、VIP特价文件处理PDF导出、Excel导出、CSV导出通知发送短信、邮件、Push传统的做法是使用if-else或switch分支判断但这会导致代码臃肿、难以维护并且每次新增一种策略都需要修改原有逻辑违反开闭原则对扩展开放对修改关闭。策略模式能很好地解决这个问题它将算法族分别封装起来让它们可以互相替换使得算法的变化独立于使用算法的客户。二、策略模式核心概念策略接口定义折扣算法的公共方法。具体策略实现接口封装具体折扣计算逻辑。上下文持有策略引用负责调用算法对外提供统一入口。在 Spring Boot 中上下文通常是一个 Service具体策略通过 IoC 容器自动注册。三、业务场景与痛点在电商系统中订单折扣规则经常变化新人首单优惠、满减折扣、会员等级折扣、限时秒杀等。传统做法是在业务代码中堆砌if-elsepublic double calculatePrice(Order order) { if (order.isNewUser()) { // 新人优惠逻辑 } else if (order.getAmount() 100) { // 满减逻辑 } else if (VIP.equals(order.getUserLevel())) { // VIP折扣 } // 每次新增规则都要修改这个方法极易出错 }这种代码违背开闭原则维护成本高测试困难。策略模式可以将每种折扣算法独立封装通过 Spring 的依赖注入实现动态切换极大增强系统扩展性。四、案例实战订单折扣系统基础版策略接口 Spring List 注入步骤1定义策略接口package com.example.discount.strategy; import com.example.discount.dto.OrderDTO; public interface DiscountStrategy { /** * 计算折扣后的金额 * param order 订单信息 * return 折扣结果包含原始金额、优惠金额、最终金额 */ DiscountResult calculate(OrderDTO order); /** * 策略标识用于客户端选择 */ String getType(); }步骤2实现两种具体策略新人折扣首单立减10元package com.example.discount.strategy; import com.example.discount.dto.OrderDTO; import com.example.discount.dto.DiscountResult; import org.springframework.stereotype.Component; Component public class NewUserDiscount implements DiscountStrategy { Override public DiscountResult calculate(OrderDTO order) { double original order.getAmount(); double discount 10.0; double finalAmount Math.max(0, original - discount); return new DiscountResult(original, discount, finalAmount, 新人首单减10元); } Override public String getType() { return new_user; } }满减折扣满100减20满200减50Component public class AmountThresholdDiscount implements DiscountStrategy { Override public DiscountResult calculate(OrderDTO order) { double original order.getAmount(); double discount 0; if (original 200) { discount 50; } else if (original 100) { discount 20; } return new DiscountResult(original, discount, original - discount, 满减折扣); } Override public String getType() { return amount_threshold; } }步骤3上下文 Service - 自动注册策略package com.example.discount.service; import com.example.discount.dto.DiscountResult; import com.example.discount.dto.OrderDTO; import com.example.discount.strategy.DiscountStrategy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.List; import java.util.Map; Service public class OrderService { Autowired private ListDiscountStrategy discountStrategies; // Spring自动注入所有策略Bean private MapString, DiscountStrategy strategyMap new HashMap(); PostConstruct public void init() { for (DiscountStrategy strategy : discountStrategies) { strategyMap.put(strategy.getType(), strategy); } } /** * 根据折扣类型计算订单最终价格 * param order 订单信息 * param discountType 折扣类型new_user / amount_threshold */ public DiscountResult applyDiscount(OrderDTO order, String discountType) { DiscountStrategy strategy strategyMap.get(discountType); if (strategy null) { throw new IllegalArgumentException(不支持的折扣类型: discountType); } return strategy.calculate(order); } }步骤4Controller 与 DTORestController RequestMapping(/order) public class OrderController { Autowired private OrderService orderService; PostMapping(/discount) public DiscountResult applyDiscount(RequestBody OrderDTO order, RequestParam String discountType) { return orderService.applyDiscount(order, discountType); } }DTOpublic class OrderDTO { private Double amount; private String userId; private Boolean newUser; // getter/setter 省略 } public class DiscountResult { private double originalAmount; private double discountAmount; private double finalAmount; private String description; // 构造方法、getter/setter 省略 }测试效果请求/order/discount?discountTypenew_user返回新人折扣请求/order/discount?discountTypeamount_threshold返回满减折扣扩展性新增“VIP折扣”时只需新建VipDiscount类实现DiscountStrategy标注Component重写getType()返回vip无需修改任何现有代码。五、进阶优化自定义注解 自动注册基础版需要每个策略手动实现getType()容易出错。我们可以使用自定义注解声明策略标识通过ApplicationContextAware自动扫描注册。5.1 自定义注解package com.example.discount.annotation; import org.springframework.stereotype.Component; import java.lang.annotation.*; Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Component // 组合Component使Spring能扫描到 public interface DiscountType { String value(); // 策略标识如 vip }5.2 修改策略类移除 getTypeDiscountType(new_user) public class NewUserDiscount implements DiscountStrategy { Override public DiscountResult calculate(OrderDTO order) { // ... 同前不再需要 getType() } }5.3 策略工厂自动注册package com.example.discount.factory; import com.example.discount.annotation.DiscountType; import com.example.discount.strategy.DiscountStrategy; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; Component public class DiscountStrategyFactory implements ApplicationContextAware { private final MapString, DiscountStrategy strategyMap new HashMap(); Override public void setApplicationContext(ApplicationContext context) throws BeansException { // 获取所有标注了 DiscountType 的 Bean MapString, Object beans context.getBeansWithAnnotation(DiscountType.class); for (Object bean : beans.values()) { if (bean instanceof DiscountStrategy) { DiscountType annotation bean.getClass().getAnnotation(DiscountType.class); strategyMap.put(annotation.value(), (DiscountStrategy) bean); } } } public DiscountStrategy getStrategy(String type) { DiscountStrategy strategy strategyMap.get(type); if (strategy null) { throw new IllegalArgumentException(未找到折扣策略: type); } return strategy; } }5.4 修改 OrderServiceService public class OrderService { Autowired private DiscountStrategyFactory factory; public DiscountResult applyDiscount(OrderDTO order, String discountType) { DiscountStrategy strategy factory.getStrategy(discountType); return strategy.calculate(order); } }优势新增策略只需编写类并添加DiscountType(xxx)零侵入完全符合开闭原则。六、动态策略选择结合枚举与前端配置很多时候折扣规则不是由前端直接传入字符串而是需要根据订单属性自动匹配。比如NewUserDiscount只对newUsertrue的订单生效。这时可以添加一个策略匹配器。6.1 增加策略的匹配条件在策略接口中添加一个supports方法public interface DiscountStrategy { DiscountResult calculate(OrderDTO order); boolean supports(OrderDTO order); // 判断是否适用于此订单 }6.2 实现匹配逻辑DiscountType(new_user) public class NewUserDiscount implements DiscountStrategy { Override public DiscountResult calculate(OrderDTO order) { ... } Override public boolean supports(OrderDTO order) { return Boolean.TRUE.equals(order.getNewUser()); } }6.3 自动匹配最佳策略Service public class OrderService { Autowired private ListDiscountStrategy strategies; // 注入所有策略 public DiscountResult applyBestDiscount(OrderDTO order) { for (DiscountStrategy strategy : strategies) { if (strategy.supports(order)) { return strategy.calculate(order); } } // 无任何策略匹配时返回无折扣 return new DiscountResult(order.getAmount(), 0, order.getAmount(), 无折扣); } }此时客户端无需传递discountType系统自动选择第一个匹配的规则。可以通过Order注解控制策略执行顺序。七、与 Spring 条件注解结合某些折扣策略只在特定环境启用如灰度发布、配置开关。使用ConditionalOnPropertyComponent ConditionalOnProperty(name discount.vip.enabled, havingValue true) DiscountType(vip) public class VipDiscount implements DiscountStrategy { // ... }在application.yml中配置discount.vip.enabled: true才加载 VIP 折扣否则忽略。八、总结与最佳实践方式适用场景优点缺点List注入 PostConstruct策略数量少标识稳定简单直观每个策略需实现getType自定义注解 工厂策略数量多团队协作零侵入高扩展稍微复杂需要工厂类supports自动匹配规则自动选择客户端无需传参无法处理多规则冲突条件注解根据配置动态装载灵活控制策略生效范围增加配置管理关键原则策略类应设计为无状态不保存实例变量保证线程安全。如果策略需要参数统一封装为 Context 对象传给策略方法。策略模式与工厂模式往往搭配使用工厂负责创建/获取策略上下文负责调用。避免“策略爆炸”当策略数量非常多时考虑使用责任链模式或规则引擎如 EasyRules、Drools。

相关文章:

Spring Boot + 策略模式:增强接口扩展性的最佳实践

一、为什么需要策略模式?在实际业务开发中,经常会遇到一个接口有多种不同实现方式的场景。例如:支付系统:微信支付、支付宝支付、银行卡支付订单折扣:满减、打折、VIP特价文件处理:PDF导出、Excel导出、CSV…...

SpringBoot+Vue实验室开放管理系统源码+论文

代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 分享万套开题报告任务书答辩PPT模板 作者完整代码目录供你选择: 《SpringBoot网站项目》1800套 《SSM网站项目》1500套 《小程序项目》1600套 《APP项目》1500套 《Python网站项目》…...

决策树在文本分类中的应用与实践

1. 文本分类与决策树基础文本分类是自然语言处理中的经典任务,而决策树作为可解释性极强的机器学习模型,在这个领域有着独特的应用价值。我第一次接触这个组合是在处理客户反馈自动分类项目时,当时需要快速构建一个能向业务部门解释的分类系统…...

2025年MLOps工程师核心能力与实战路线

1. 2025年MLOps精通的战略路径解析过去三年间,我主导过七个不同规模的MLOps落地项目,从金融风控到工业质检,最深的体会是:MLOps工程师正在从"会调参的码农"转变为"懂业务的架构师"。2025年的MLOps知识图谱将呈…...

what is 卡常?

卡常的概念与定义 卡常指在编程竞赛或算法实现中&#xff0c;通过优化代码细节使程序在时间或空间限制内运行。这种优化通常针对特定评测环境&#xff0c;目的是通过微调代码来通过严格的时间或空间限制。 说人话 例//我是正解 #include<bits/stdc.h> using namespace st…...

GitHub宝藏库awesome-llm-apps:LLM应用开发灵感与实战指南

1. 项目概述&#xff1a;一个汇聚LLM应用灵感的“藏宝图”最近在GitHub上闲逛&#xff0c;发现了一个让我眼前一亮的仓库&#xff1a;Shubhamsaboo/awesome-llm-apps。这可不是一个普通的代码库&#xff0c;它更像是一张由全球开发者共同绘制的“藏宝图”&#xff0c;专门标记那…...

TCP、UDP、ARP、Socket 与网络加密协议知识点整理——【2026】软考中级知识整理

TCP、UDP、ARP、Socket 与网络加密协议知识点整理 在计算机网络中&#xff0c;TCP、UDP、IP、ARP、ICMP、Socket、PPP、IPSec 等概念经常一起出现&#xff0c;也容易混淆。本文主要从协议层次、核心作用、典型应用和考试常见考点几个角度进行整理。 出自&#xff1a;智澈乐尚网…...

深度强化学习实战:从DQN到PPO的算法实现与调参指南

1. 项目概述与核心价值如果你对深度强化学习&#xff08;Deep Reinforcement Learning, DRL&#xff09;感兴趣&#xff0c;并且不止一次地尝试过复现论文里的算法&#xff0c;结果却卡在环境配置、代码调试或者算法细节的“最后一公里”上&#xff0c;那么这个名为“awjuliani…...

【Backend Flow工程实践 08】LEF / Liberty / Verilog / DEF:Backend Flow 为什么依赖多格式协同?

作者&#xff1a;Darren H. Chen 方向&#xff1a;Backend Flow / 后端实现流程 / 工程自动化 / 验证基础设施 demo&#xff1a;LAY-BE-08_standard_formats 标签&#xff1a;EDA、Backend Flow、后端实现、LEF、Liberty、Verilog、DEF、标准格式、Design Import、Library Cont…...

惯性摩擦焊机早期故障检测与排除技术实现【附代码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、EI、SCI写作与指导&#xff0c;毕业论文、期刊论文经验交流。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;查看文章底部二维码 &#xff08;1&#xff09;两重分段威布尔模型与早期故障拐点求解&#xff1…...

零基础极速上手:普通人如何用AI建站工具10分钟搭建个人网站

零基础极速上手&#xff1a;普通人如何用AI建站工具10分钟搭建个人网站很多人觉得搭建网站是程序员和设计师的专属技能&#xff0c;自己完全不懂技术&#xff0c;就算有AI帮忙也无从下手。其实&#xff0c;当下的AI建站工具已经将这个过程简化到了极致&#xff1a;你只需要像聊…...

幼儿识字动画 1000 字 动画

本文为家庭学习整理资料&#xff0c;仅供个人学习使用&#xff0c;侵删。 资源名称&#xff1a;幼儿识字动画 1000 字 动画 适合年龄&#xff1a;3–8 岁 内容简介&#xff1a;系统识字动画&#xff0c;帮助孩子轻松掌握 1000 个常用字。 学习资料获取方式&#xff1a; ht…...

AI建站工具怎么选:一份中立实用的选型标准与对比指南

AI建站工具怎么选&#xff1a;一份中立实用的选型标准与对比指南面对市面上五花八门的AI建站工具&#xff0c;很多人都会陷入选择困难。是选那个号称完全不用写代码的&#xff0c;还是选那个功能看起来更强大的&#xff1f;生成的代码能不能商用&#xff1f;会不会有安全隐患&a…...

DBO-VMD-HT高压直流线路故障定位系统设计【附代码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、EI、SCI写作与指导&#xff0c;毕业论文、期刊论文经验交流。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;查看文章底部二维码 &#xff08;1&#xff09;蜣螂优化算法自适应优化VMD参数&#xff1a; 针对…...

AI智能体文件感知规划:让AI在行动前先读懂你的文件

1. 项目概述&#xff1a;当AI规划器学会“读文件”最近在折腾AI智能体&#xff08;Agent&#xff09;和自动化工作流&#xff0c;我发现一个挺有意思的痛点&#xff1a;很多规划任务&#xff0c;比如写周报、整理会议纪要、分析数据&#xff0c;其实都离不开对现有文件的处理。…...

医疗AI训练数据安全红线(MCP 2026脱敏配置终极 checklist)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;医疗AI训练数据安全红线的法律与伦理基线 医疗AI模型的训练高度依赖高质量、大规模、标注精准的临床数据&#xff0c;但此类数据天然承载患者隐私、生命权益与社会信任。因此&#xff0c;数据采集、脱敏…...

多智能体系统在医疗领域的应用:架构设计与工程实践

1. 项目概述&#xff1a;一个面向医疗领域的多智能体协作系统最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“Multi-Agent-Medical-Assistant”。光看名字&#xff0c;就能猜到它想干什么&#xff1a;用多个AI智能体来协作&#xff0c;扮演一个医疗助理的角色。这其实戳…...

MCP国产化部署卡在麒麟V10?手把手教你绕过OpenEuler兼容性雷区(附调试日志对照表)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;MCP国产化部署卡在麒麟V10&#xff1f;手把手教你绕过OpenEuler兼容性雷区&#xff08;附调试日志对照表&#xff09; 在麒麟V10 SP1&#xff08;内核 4.19.90-23.8.v2101.ky10.aarch64&#xff09;上部…...

多模态大模型实战:从Mistral-ViBE架构解析到图文理解应用部署

1. 项目概述&#xff1a;从“氛围”到“多模态”的智能进化最近在折腾大模型应用时&#xff0c;发现了一个挺有意思的仓库&#xff1a;mistralai/mistral-vibe。乍一看名字&#xff0c;你可能会联想到音乐或者某种情绪&#xff0c;但在AI圈子里&#xff0c;这个名字指向的是Mis…...

汽修门店 POS 机断网?映翰通 IR615 工业路由器搞定稳定联网

一、门店痛点&#xff1a;收银断网&#xff0c;生意白跑汽车维修门店的 POS 机&#xff0c;是日常运营的核心。有线宽带不稳、信号差&#xff0c;付款高峰期频繁断网&#xff0c;订单卡单、失败普通家用路由器扛不住门店复杂环境&#xff0c;用不久就宕机交易数据传输没保障&am…...

MIG环境下GPU共享资源调度优化与碎片整理策略

1. MIG环境下GPU共享工作负载的调度挑战与解决方案在AI推理、科学计算等需要大规模并行计算的场景中&#xff0c;GPU资源的高效利用一直是数据中心管理的核心难题。NVIDIA推出的多实例GPU&#xff08;Multi-Instance GPU&#xff0c;MIG&#xff09;技术通过硬件级分区实现了资…...

推理优化:大模型高效部署核心技术全解析

随着大语言模型、多模态模型规模持续扩张&#xff0c;AI模型在各类业务场景落地时&#xff0c;推理性能瓶颈愈发凸显。高延迟、低吞吐量、硬件资源利用率不足等问题&#xff0c;直接影响用户体验与业务成本&#xff0c;推理优化成为AI工程化落地的核心环节。本文将从推理基础认…...

MCP 2026资源调度算法深度调优:从吞吐量下降47%到P99延迟压至8ms的7步实战法

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;MCP 2026资源调度算法优化的背景与挑战 随着大规模异构计算平台&#xff08;MCP&#xff09;在AI训练、实时推理与边缘协同场景中的深度部署&#xff0c;2026年新一代MCP架构对资源调度提出了前所未有的…...

太阳能路灯选技术,看准这三点不踩坑

在“双碳”目标与乡村振兴战略的双重驱动下&#xff0c;太阳能路灯的应用场景正从乡村小路向市政主干道、工业园区、景区步道全面延伸。然而&#xff0c;面对市场上“质保三年”“终身维护”等宣传口号&#xff0c;不少采购方却在实际使用中遭遇“阴影”——晴天亮&#xff0c;…...

一篇讲透:Java并发与线程安全,新手看完永久不踩坑

文章目录前言&#xff1a;写给所有普通业务开发的真心话一、先掰扯明白三个核心词&#xff08;大白话定义简易代码示例&#xff0c;看完绝不迷糊&#xff09;老开发真心话&#xff1a;为什么我很多年没碰过并发&#xff0c;系统也没崩&#xff1f;1.1 什么是并发编程&#xff1…...

AI应用数据平台datapizza-ai:从架构设计到实战部署全解析

1. 项目概述&#xff1a;一个为AI应用量身定制的数据平台最近在折腾AI应用开发&#xff0c;从原型验证到规模化部署&#xff0c;有一个问题反复出现&#xff0c;而且越来越棘手&#xff1a;数据。这里的“数据”不是指训练大模型用的海量语料&#xff0c;而是指应用运行过程中产…...

构建智能视频数据库:从多模态分析到导演式检索的工程实践

1. 项目概述&#xff1a;从“视频数据库”到“导演”的智能进化最近在折腾一个挺有意思的项目&#xff0c;我把它叫做“video-db/Director”。这个名字乍一看有点抽象&#xff0c;拆开来看&#xff0c;“video-db”指向视频数据库&#xff0c;而“Director”则是导演。合在一起…...

从操作数到智能体:构建可执行任务AI系统的核心架构与实践

1. 项目概述&#xff1a;从“操作数”到“智能体”的范式跃迁最近在跟几个做AI应用落地的朋友聊天&#xff0c;大家普遍有个感觉&#xff1a;单纯调用大模型API做个聊天界面&#xff0c;或者用RAG&#xff08;检索增强生成&#xff09;做个知识库问答&#xff0c;已经越来越“卷…...

AI助手配置管理工具cursor-kit:统一管理Cursor、Copilot、AntiGravity配置

1. 项目概述&#xff1a;AI助手配置管理工具如果你和我一样&#xff0c;日常开发重度依赖Cursor、GitHub Copilot这类AI编程助手&#xff0c;那你一定遇到过这个痛点&#xff1a;每次新建一个项目&#xff0c;都得手动去复制粘贴那些精心调教好的.cursorrules文件、自定义指令模…...

基于LLM与向量数据库的智能体框架Lore:构建私有知识库AI助手

1. 项目概述&#xff1a;一个为知识库注入灵魂的智能体框架 最近在折腾个人知识库和AI智能体&#xff0c;发现了一个让我眼前一亮的开源项目&#xff1a;Lore。这名字起得挺有意思&#xff0c;“Lore”在英文里是“学问”、“传说”的意思&#xff0c;它给自己的定位是“为你的…...