常用设计模式在 Spring Boot 项目中的实战案例

引言​

在当今的软件开发领域,Spring Boot 以其高效、便捷的特性成为构建 Java 应用程序的热门框架。而设计模式作为软件开发中的宝贵经验总结,能够显著提升代码的可维护性、可扩展性和可复用性。本文将深入探讨几种常用设计模式在 Spring Boot 项目中的实际应用,通过具体案例帮助读者更好地理解和掌握这些设计模式在实际开发中的运用技巧。

一、工厂模式

场景描述​

假设我们正在开发一个电商系统,其中有多种不同类型的订单,如普通订单、促销订单、团购订单等。每种订单在处理时都有一些独特的逻辑,例如促销订单需要计算优惠金额,团购订单需要处理成团逻辑等。我们可以使用工厂模式来根据订单类型创建不同的订单处理对象。​

代码实现

1.定义订单处理接口

public interface OrderProcessor {void processOrder();
}

2.创建具体的订单处理类

  • 普通订单处理类
@Component
public class NormalOrderProcessor implements OrderProcessor {@Overridepublic void processOrder() {System.out.println("Processing normal order...");}
}
  • 促销订单处理类
@Component
public class PromotionOrderProcessor implements OrderProcessor {@Overridepublic void processOrder() {System.out.println("Processing promotion order, calculating discounts...");}
}

3.创建订单工厂类

@Component
public class OrderFactory {@Autowiredprivate Map<String, OrderProcessor> orderProcessorMap;public OrderProcessor getOrderProcessor(String orderType) {return orderProcessorMap.get(orderType);}
}

4.在服务层使用工厂类

@Service
public class OrderService {@Autowiredprivate OrderFactory orderFactory;public void process(String orderType) {OrderProcessor orderProcessor = orderFactory.getOrderProcessor(orderType);if (orderProcessor != null) {orderProcessor.processOrder();} else {System.out.println("No suitable order processor found for type: " + orderType);}}
}

优势分析​

通过工厂模式,我们将对象的创建和使用分离,当需要新增订单类型时,只需创建新的订单处理类并在配置中注册,无需修改大量现有代码,提高了系统的可扩展性。​

二、单例模式​

场景描述​

在 Spring Boot 项目中,经常会有一些资源或对象只需要一个实例,例如数据库连接池、日志记录器等。以日志记录器为例,我们希望整个应用程序中只有一个日志记录器实例,以确保日志记录的一致性和高效性。​

代码实现

1.使用 Spring 的注解实现单例

@Component
public class CustomLogger {private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CustomLogger.class);public void logMessage(String message) {logger.info(message);}
}

在 Spring 中,默认情况下,通过@Component注解创建的 Bean 就是单例模式。当其他组件需要使用CustomLogger时,直接注入即可。

@Service
public class SomeService {@Autowiredprivate CustomLogger customLogger;public void doSomething() {customLogger.logMessage("Service is doing something...");}
}

优势分析​

单例模式确保了系统中特定资源或对象的唯一性,避免了资源的重复创建和浪费,提高了系统性能和资源利用率,同时也方便了对共享资源的管理和维护。​

三、代理模式​

场景描述​

假设我们有一个业务方法,在调用该方法前后需要添加一些通用的逻辑,比如权限验证、日志记录等。我们可以使用代理模式来实现这些横切关注点,而无需在每个业务方法中重复编写相同的代码。​

代码实现

1.定义业务接口

public interface UserService {void doBusinessLogic();
}

2.创建真实业务类

@Service
public class UserServiceImpl implements UserService {@Overridepublic void doBusinessLogic() {System.out.println("Doing business logic...");}
}

3.创建代理类

@Aspect
@Component
public class UserServiceProxy {@Around("execution(* com.example.demo.service.UserService.doBusinessLogic(..))")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before business logic - checking permissions");Object result = joinPoint.proceed();System.out.println("After business logic - logging");return result;}
}

优势分析​

代理模式将核心业务逻辑与辅助性的横切逻辑分离,使代码更加清晰、可维护。通过代理类,我们可以方便地在不修改原有业务代码的基础上添加新的功能,符合开闭原则。

四、策略模式​

场景描述​

继续以电商系统为例,系统中有多种不同的运费计算方式,如按重量计算、按订单金额计算、固定运费等。为了能够灵活地切换和管理这些运费计算方式,我们可以运用策略模式。​

代码实现

1.定义运费计算策略接口

public interface ShippingFeeStrategy {double calculateShippingFee(double weight, double orderAmount);
}

2.创建具体的运费计算策略类

  • 按重量计算运费策略类
@Component
public class WeightBasedShippingStrategy implements ShippingFeeStrategy {@Overridepublic double calculateShippingFee(double weight, double orderAmount) {// 假设每千克运费为10元return weight * 10;}
}
  • 按订单金额计算运费策略类
@Component
public class OrderAmountBasedShippingStrategy implements ShippingFeeStrategy {@Overridepublic double calculateShippingFee(double weight, double orderAmount) {// 假设订单金额满100免运费,否则收取10元运费return orderAmount >= 100? 0 : 10;}
}
  • 固定运费策略类
@Component
public class FixedShippingStrategy implements ShippingFeeStrategy {@Overridepublic double calculateShippingFee(double weight, double orderAmount) {// 固定运费为5元return 5;}
}

3.创建运费计算服务,使用策略模式

@Service
public class ShippingFeeService {@Autowiredprivate Map<String, ShippingFeeStrategy> shippingFeeStrategyMap;public double calculate(String strategyType, double weight, double orderAmount) {ShippingFeeStrategy strategy = shippingFeeStrategyMap.get(strategyType);if (strategy != null) {return strategy.calculateShippingFee(weight, orderAmount);} else {throw new IllegalArgumentException("No suitable shipping fee strategy found for type: " + strategyType);}}
}

优势分析​

策略模式使得不同的运费计算算法可以独立变化,符合开闭原则。当需要新增运费计算方式时,只需创建新的策略类并实现接口,然后在配置中注册即可,无需修改现有业务代码,大大提高了系统的灵活性和可维护性。同时,不同的策略类可以被复用,提高了代码的复用性。

补充

也可以自定义Match接口实现策略模式,大致思路如下:

1.定义Match接口

public interface Match<T> {boolean match(T var1);
}

2.业务接口继承Match接口

public interface BusinessHandler extends Match<String> {/*** 业务执行方法** @param context 上下文*/void execute(BusinessContext context);
}

3.特定策略类实现业务接口

类一:

@Slf4j
@Component
public class ExactMatchSort implements BusinessHandler {@Setter(onMethod_ = @Autowired)BusinessService businessService;/*** {@inheritDoc}*/@Overridepublic boolean match(String value) {return RuleEnum.EXACT_MATCH.getCode().equals(value);}/*** {@inheritDoc}*/@Overridepublic void execute(BusinessContext context) {// 自定义业务逻辑businessService.exactMatch(context);}
}

类二:

@Slf4j
@Component
public class FuzzyMatchSort implements BusinessHandler {@Setter(onMethod_ = @Autowired)BusinessService businessService;/*** {@inheritDoc}*/@Overridepublic boolean match(String value) {return RuleEnum.FUZZY_MATCH.getCode().equals(value);}/*** {@inheritDoc}*/@Overridepublic void execute(BusinessContext context) {// 自定义业务逻辑businessService.fuzzyMatch(context);}
}

4.定义抽象策略管理器

public abstract class AbstractProcessorManage<T, P extends Match<T>> {private List<P> processorList;public AbstractProcessorManage() {}@Autowiredpublic void setProcessorList(List<P> processorList) {this.processorList = processorList;}public abstract String getCannotMatchMessage();public P getProcessor(T t) {for(P p : this.processorList) {if (p.match(t)) {return p;}}throw new RuntimeException(this.getCannotMatchMessage());}
}

5.定义业务策略管理器

/*** 策略管理器*/
@Component
public class BusinessManger extends AbstractProcessorManage<String, BusinessHandler> {/*** {@inheritDoc}*/@Overridepublic String getCannotMatchMessage() {return "非法的策略";}
}

6.业务流程调用

/*** 业务执行类**/
@Slf4j
@Component
public class StockFilterManager {@Setter(onMethod_ = @Autowired)private BusinessManger businessManger;private void businessExcute(BusinessContext context) {businessManger.getProcessor(context.value).execute(context);}
}

这仅是基础架构,也可以在内层嵌套更多的设计模式,以保证代码的可读性与可维护性。

结论

通过以上在 Spring Boot 项目中的实战案例,我们看到了工厂模式、单例模式、代理模式以及策略模式在不同场景下的应用及其带来的显著优势。在实际项目开发中,合理运用设计模式能够极大地提升代码质量,使项目更加健壮、灵活和易于维护。希望读者通过本文的学习,能够在自己的 Spring Boot 项目中熟练运用这些设计模式,打造出更优秀的软件系统。

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

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

相关文章

《饶议科学》阅读笔记

《饶议科学》 《偷窃的生物学机制&#xff1a;&#xff08;有些&#xff09;小偷有药可治》阅读笔记 核心内容&#xff1a;探讨偷窃狂&#xff08;kleptomania&#xff09;的生物学机制及相关研究。具体要点 偷窃狂的特征&#xff1a;患者不可抑制地反复偷窃个人不需要、与金钱…

从零开始搭建第一个Spring Boot应用:从入门到精通

1. Spring Boot简介与核心概念 1.1 什么是Spring Boot&#xff1f; Spring Boot是Spring框架的一个扩展&#xff0c;它简化了基于Spring的应用程序的初始搭建和开发过程。通过自动配置和约定优于配置的原则&#xff0c;Spring Boot让开发者能够快速启动和运行项目。 通俗理解…

c# LINQ-Query01

文章目录 查询数据源标准查询分两类即时查询已推迟流式处理非流式处理分类表聚合Aggregate<TSource,TAccumulate,TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate,TSource,TAccumulate>, Func<TAccumulate,TResult>)Aggregate<TSour…

AI恶魔之眼使用说明书

AI恶魔之眼使用说明书 产品简介 1.1 产品介绍 AI恶魔之眼是一款具备动态视觉效果与仿生眼睛模拟功能的智能显示产品&#xff0c;可实现以下特性&#xff1a; 真实人眼模拟&#xff1a;支持虹膜样式变换、眨眼动画、瞳孔缩放等动态特效&#xff0c;仿真度高自定义内容上传&am…

CAN报文逆向工程

在没有DBC文件的情况下解析CAN报文获取物理信息需要逆向工程和系统分析。以下是详细步骤&#xff1a; 1. 数据采集与基础分析 采集原始数据&#xff1a; 使用CAN分析工具&#xff08;如PCAN-Explorer、SavvyCAN或USB-CAN适配器配套软件&#xff09;记录车辆在不同状态下的CAN数…

KL散度(Kullback-Leibler Divergence):概率分布差异的量化利器

目录 1. 什么是KL散度?关键特点:2. KL散度的数学公式离散分布的KL散度公式:连续分布的KL散度公式:3. KL散度的计算示例示例1:离散分布示例2:连续分布(高斯分布)4. KL散度的核心性质1. 非对称性2. 非负性3. 与熵的关系5. KL散度与相关性的关系1. KL散度 ≠ 相关性2. 间接…

二叉树的遍历与构造

唉&#xff0c;好想回家&#xff0c;我想回家跟馒头酱玩&#xff0c;想老爸老妈。如果上天再给我一次选择的机会&#xff0c;我会选择当一只小动物&#xff0c;或者当棵大树也好&#xff0c;或者我希望自己不要有那么多多余的情绪&#xff0c;不要太被别人影响&#xff0c;开心…

leetcode 141. Linked List Cycle

题目描述&#xff1a; 代码&#xff1a; 用哈希表也可以解决&#xff0c;但真正考察的是用快慢指针法。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Soluti…

AI辅助DevOps与自动化测试:重构软件工程效率边界

随着AI技术渗透至软件开发生命周期&#xff0c;DevOps与自动化测试领域正经历颠覆性变革。本文系统性解析AI在需求分析、测试用例生成、部署决策、异常检测等环节的技术实现路径&#xff0c;结合微软Azure DevOps、Tesla自动驾驶测试等典型场景&#xff0c;探讨AI如何突破传统效…

5月7号.

flex布局: 表单标签: 表单标签-表单项:

【AI面试准备】中文分词与实体抽取技术详解

分词&#xff0c;词性标准 目录 一、分词与词性标注1. **分词&#xff08;Word Segmentation&#xff09;**2. **词性标注&#xff08;Part-of-Speech Tagging&#xff09;** 二、实体抽取&#xff08;Named Entity Recognition, NER&#xff09;1. **实体类型示例**2. **输出…

【AI落地应用实战】Amazon Bedrock 零门槛使用 DeepSeek-R1:在 Amazon Bedrock 上部署与调用的完整实践指南

随着大语言模型&#xff08;LLM&#xff09;技术的快速发展&#xff0c;企业和开发者对具备更强理解与生成能力的模型需求也愈加旺盛。DeepSeek-R1 作为 DeepSeek 公司推出的一款强大开源模型&#xff0c;不仅在多项评测中表现优异&#xff0c;更具备出色的推理能力和长文本处理…

阿里云平台与STM32的物联网设计

基于阿里云平台与STM32的物联网设计方案可结合硬件选型、通信协议、云端配置及功能实现等多个维度进行设计。以下是综合多个参考案例的详细设计方案&#xff1a; 一、硬件选型与架构设计 主控芯片选择 STM32系列&#xff1a;推荐使用STM32F103&#xff08;如STM32F103ZET6、STM…

IBM BAW(原BPM升级版)使用教程Toolkit介绍

本部分为“IBM BAW&#xff08;原BPM升级版&#xff09;使用教程系列”内容的补充。 一、系统Toolkit 在 IBM Business Automation Workflow (BAW) 中&#xff0c;System Toolkit 是一组预先定义和配置好的工具、功能和组件&#xff0c;旨在帮助流程设计者和开发人员快速构建…

力扣-hot100 (矩阵置零)

73. 矩阵置零 中等 给定一个 *m* x *n* 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示…

安装并运行第一个Spark程序

安装并运行第一个Spark程序需要完成以下步骤&#xff1a;安装Java和Spark&#xff0c;配置环境变量&#xff0c;编写并运行Spark程序。以下是详细的教程&#xff1a; 1. 安装Java Spark需要Java运行环境&#xff08;JRE&#xff09;或Java开发工具包&#xff08;JDK&#xff…

Python Selenium爬虫功能使用介绍

本文介绍python selenium 爬虫的功能以及使用 1. 基础核心功能 浏览器控制 from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager# 自动管理浏览器驱动 driver webdriver.Chro…

Cloudera CDP 7.1.3 主机异常关机导致元数据丢失,node不能与CM通信

问题描述 plaintext ERROR Could not load post-deployment data from /var/run/cloudera-scm-agent/process/ccdeploy_hadoop-conf_etchadoopconf.cloudera.yarn_-8903374259073700469 IOError: [Errno 2] No such file or directory: /var/run/cloudera-scm-agent/proce…

Nginx安全防护与HTTPS部署

目录 Nginx 隐藏版本号 限制危险请求方法 请求限制&#xff08;CC攻击防御&#xff09; 压力测试 防盗链 防止防盗链 动态黑名单 自动添加黑名单 HTTPS配置 HTTPS 概念 安全通信的四大原则 HTTPS的几种加密方式 nginx https的作用 Nginx 隐藏版本号 &#xff01;&#xff01;&a…

C++类对象的隐式类型转换和编译器返回值优化

文章目录 前言1. 隐式类型转换1.1 单参数的隐式类型转换1.2 多参数的隐式类型转换1.3 explicit关键字 2. 编译器的优化2.1 普通构造优化2.2 函数传参优化2.3 函数返回优化 前言 在类与对象的学习过程中&#xff0c;一定会对隐式类型转换这个词不陌生。对于内置类型而言&#x…