解锁Spring Boot中的设计模式—05.策略模式:探索【策略模式】的奥秘与应用实践!

news/发布时间2024/5/16 7:37:58

1.策略者工厂模式(Map版本)

1.需求背景

假设有一个销售系统,需要根据不同的促销活动对商品进行打折或者其他形式的优惠。这些促销活动可以是针对不同商品类别的,比如男装、女装等。

2.需求实现
  1. 活动策略接口:定义了所有促销活动的公共接口,包括展示活动的方法。
  2. 具体策略活动:实现了活动策略接口的具体策略类,每个具体策略类代表一种促销活动,比如活动A和活动B。
  3. 连接策略的上下文:即环境角色,用于连接具体的促销活动和客户端。它持有一个策略对象,根据客户端的需求展示对应的活动。
  4. 策略工厂:提供了一种根据活动类型获取对应策略对象的方法,以便客户端根据需要选择促销活动。
3.策略者模式优点
  • 提供了对开闭原则的支持,可以灵活增加新的促销活动而无需修改现有代码。
  • 避免了使用多重条件语句,提高了代码的可读性和可维护性。
  • 可以方便地管理和组织相关的算法族,提高了代码的组织性和复用性。
4.策略者模式缺点
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类,因此不适用于客户端不知道所有算法或行为的情况。
  • 可能会造成策略类的过多,每个具体策略类都会产生一个新类,增加了系统的复杂性。
5.应用场景
  • 当一个系统中存在多种相似但不同的算法或行为,并且需要动态切换时,可以考虑使用策略者模式。
  • 当需要在不修改现有代码的情况下灵活地增加新的算法或行为时,策略者模式也是一个不错的选择。

策略者模式在销售系统、支付系统、游戏开发等领域都有广泛的应用。

实现

1.1.具体策略活动
/*** 具体策略活动A*/
public class StrategyA implements Strategy {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Overridepublic void show() {logger.error("活动A,减999!");}
}/*** 活动B*/
public class StrategyB implements Strategy {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@Overridepublic void show() {logger.error("活动B,减999999!");}
}
1.2.所有策略的公共接口
/*** 定义所有活动的公共接口*/
public interface Strategy {void show();}
1.3.连接策略的上下文
/*** 定义环境角色(Context):用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员*/
public class ManStrategy {/*** 持有策略者角色的应用(传入啥执行啥)* SalesMan salesMan = new SalesMan(new StrategyA());* SalesMan salesManB = new SalesMan(new StrategyB());*/private Strategy strategy;/*** 初始化时 将具体的策略者 赋值给当前策略者引用* @param strategy*/public ManStrategy(Strategy strategy){this.strategy = strategy;}/*** 展示具体的策略*/public void showInfoStrategy(){strategy.show();}
}
1.4.策略工厂
public class HandlerStrategyFactory {private static final Map<String, Strategy> map = new HashMap<>();static {map.put("男装",new StrategyA());map.put("女装",new StrategyB());}public static Strategy getStrategy(String type){return map.get(type);}
}
1.5.测试
public class StrategyDemo {public static void main(String[] args) {// 对象模式ManStrategy manStrategy = new ManStrategy(new StrategyB());manStrategy.showInfoStrategy();// --------------------------- map集合 --------------------------// 根据对应各key 找到对应的实现类 然后执行对应方法 MAP集合 方式Strategy strategy = HandlerStrategyFactory.getStrategy("女装");strategy.show();}
}

在这里插入图片描述

2.策略工厂模式(Spring版本)

1. 简介

策略工厂模式是一种行为型设计模式,用于灵活选择不同算法,而不必改变代码结构。

2. 核心思想
  • 定义抽象策略接口和具体策略类。
  • 实现策略工厂,根据需求选择合适的策略类。
3. 案例背景

电商系统需要根据不同促销活动对商品进行打折,促销策略基于活动季节、产品类型等选择。

4. 示例要点
  • 定义抽象策略接口:PromotionStrategy,包含applyDiscount()方法。
  • 创建具体促销策略类如SpringFestivalPromotionMemberDayPromotion
  • 实现策略工厂PromotionStrategyFactory,根据需求选择合适的促销策略。
5. 应用场景
  • 需要根据不同条件选择合适算法。
  • 系统需要在不同环境下灵活切换算法。

策略工厂模式提供了灵活性和可维护性,使系统更加健壮。

2.1.类图

在这里插入图片描述

3.具体实现

3.1.抽象策略接口

/*** 抽象策略接口*/
public interface PromotionStrategy<R,T,U> {/*** 应用折扣* @param t 商品信息* @param u 用户信息* @return 折扣后的最终价格*/R applyDiscount(T t, U u);
}

3.2.策略具体实现类

3.2.1.春节促销策略实现类
package com.hrfan.java_se_base.pattern.strategy_pattern;import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import java.math.BigDecimal;/*** 春节促销 策略实现类*/
@Service
public class SpringFestivalPromotion implements PromotionStrategy<BigDecimal, String, UserInfoToken> {private final Logger logger = LoggerFactory.getLogger(SpringFestivalPromotion.class);/*** 春节折扣信息* @param goodsName 商品信息* @param userInfoToken 用户信息* @return*/@Overridepublic BigDecimal applyDiscount(String goodsName, UserInfoToken userInfoToken) {logger.error("============= {},春节大促销,原价100,现在6折 =============",goodsName);BigDecimal account = new BigDecimal("100");BigDecimal res = account.multiply(new BigDecimal("0.6")).setScale(2,BigDecimal.ROUND_HALF_UP);logger.error("============= 最终价格仅为:{},速来抢购! =============",res);return res;}
}
3.2.2.会员日策略实现类
package com.hrfan.java_se_base.pattern.strategy_pattern;import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import java.math.BigDecimal;/*** 会员日策略实现类*/
@Service
public class MemberDayPromotion implements PromotionStrategy<BigDecimal,String, UserInfoToken> {private final Logger logger = LoggerFactory.getLogger(MemberDayPromotion.class);/*** 会员日商品促销策略* @param goodsName 商品信息* @param userInfoToken 用户信息* @return 最终优惠后的价格*/@Overridepublic BigDecimal applyDiscount(String goodsName, UserInfoToken userInfoToken) {logger.error("============= {},会员日大促销,原价100,现在3折 =============",goodsName);BigDecimal account = new BigDecimal("100");BigDecimal res = account.multiply(new BigDecimal("0.3")).setScale(2,BigDecimal.ROUND_HALF_UP);logger.error("============= 最终价格仅为:{},速来抢购! =============",res);return res;}
}

3.3.创建策略工厂

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;/*** 策略工厂*/
@Service
public class PromotionStrategyFactory {@Resourceprivate ApplicationContext context;/*** 选择对应的策略*/public PromotionStrategy createPaymentStrategy(String paymentMethod) {try {return context.getBean(paymentMethod, PromotionStrategy.class);}catch (Exception e){e.printStackTrace();throw new RuntimeException("未匹配到对应策略:" + paymentMethod);}}
}

4.测试

import com.hrfan.java_se_base.config.ResultObject;
import com.hrfan.java_se_base.log.model.UserInfoToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.math.BigDecimal;/*** 策略模式测试方法*/
@RestController
@RequestMapping("/v1/strategy/")
public class StrategyController {@Resourceprivate PromotionStrategyFactory promotionStrategyFactory;@PostMapping("/getLastPrice")public ResultObject getLastPrice(@RequestParam("type") String type, UserInfoToken userInfoToken){ResultObject instance = ResultObject.createInstance(true);// 获取商品的最终价格 (根据传入的策略然后选择对应的实现类 该type就是对应实现类的名称)PromotionStrategy strategy = promotionStrategyFactory.createPaymentStrategy(type);BigDecimal res = (BigDecimal) strategy.applyDiscount("鸡蛋", userInfoToken);instance.setData(res);instance.setMessage("获取成功!");return instance;}
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

策略工厂模式 vs 普通策略模式:区别总结

1. 概念
  • 策略工厂模式: 策略工厂模式是策略模式的一种变体,它将策略的选择和创建交给了工厂类来处理,客户端通过工厂获取需要的具体策略对象。
  • 普通策略模式: 普通策略模式直接由客户端选择和创建具体的策略对象,客户端需要明确知道每个策略类的存在,并负责创建相应的对象。
2. 结构
  • 策略工厂模式: 策略工厂模式包含策略接口、具体策略类和策略工厂类。客户端通过策略工厂类获取具体的策略对象。
  • 普通策略模式: 普通策略模式包含策略接口和具体策略类。客户端直接选择和创建具体的策略对象。
3. 使用场景
  • 策略工厂模式: 适用于需要根据条件选择不同策略,并且需要将策略选择逻辑与客户端分离的场景。适用于策略类较多,客户端不需要直接了解每个策略类的情况。
  • 普通策略模式: 适用于策略较少,客户端可以直接了解并选择每个策略类的情况。
4. 灵活性
  • 策略工厂模式: 策略工厂模式更加灵活,可以动态地切换策略,不需要修改客户端代码。
  • 普通策略模式: 普通策略模式相对固定,客户端需要显式地选择并创建具体的策略对象。
5. 维护性
  • 策略工厂模式: 策略工厂模式使得系统更易于扩展和维护,添加新的策略只需修改工厂类。
  • 普通策略模式: 普通策略模式需要客户端直接了解每个策略类,维护起来相对困难。
6. 总结
  • 策略工厂模式: 提供了更高的灵活性和可维护性,将策略的选择和创建与客户端分离。
  • 普通策略模式: 简单直接,适用于策略较少,且客户端能够明确选择每个策略类的情况。

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

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

相关文章

Fiddler抓包(网页、手机、MUMU模拟器)

前置条件&#xff1a;电脑上下载安装好了Fiddler&#xff0c;有浏览器 一、网页抓包 1、fiddler下载安装证书 Tools-Options 勾选下面两个框 点击下面的选项&#xff0c;信任证书 会弹出弹窗&#xff0c;点击yes&#xff08;这个时候注意&#xff0c;DO_NOT_TRUST_FiddlerRo…

2024.2.20

1、用多进程完成两个文件的拷贝 #include<myhead.h> int main(int argc, const char *argv[]) {pid_t pid-1;FILE *fpNULL;FILE *fp2NULL;//打开文件if((fpfopen(argv[1],"r"))NULL){perror("fopen error");return -1;}if((fp2fopen(argv[2],"…

Docker 镜像仓库是什么?有哪些镜像仓库命令?

1. Docker 的架构 &#xff08;图片来源&#xff1a;Docker架构图&#xff09; Registry&#xff08;Docker 仓库&#xff09; &#xff1a; Docker 仓库用来保存镜像&#xff0c;Docker 官方提供了一个公共的 Docker 仓库&#xff0c;称为 Docker Hub&#xff0c;开发者可以在…

JVM对象的创建流程与内存分配

对象的创建流程与内存分配 创建流程对象内存分配方式内存分配安全问题对象内存分配流程【重要】:对象怎样才会进入老年代?重点 案例演示:对象分配过程大对象直接进入老年代02-对象内存分配的过程: 创建流程 加载 验证 解析 准备 初始化 使用 写在 对象内存分配方式 内存分配…

什么是智慧公厕?智慧公厕实现公共厕所的高效管理

在城市的各个区域和场所&#xff0c;公共厕所是人们生活中不可或缺的一部分。然而&#xff0c;传统的公厕管理方式存在诸多问题&#xff0c;如维护不及时、清洁不到位、设备老化等&#xff0c;给人们的生活与出行带来了不便和困扰。为了解决这些问题&#xff0c;智慧公厕成为一…

phaseDNN文章解读

文章DOI: https://doi.org/10.48550/arXiv.1905.01389 作者是 Southern Methodist University 的Wei Cai 教授 A Parallel Phase Shift Deep Neural Network for Adaptive Wideband Learning 一种并行移相深度神经网络来自适应学习宽带频率信号 20190514 核心思想&#xff1a;…

如何系统地自学Python?

如何系统地自学Python&#xff1f; 如何系统地自学Python&#xff1f;1.了解编程基础2.学习Python基础语法3.学习Python库和框架4.练习编写代码5.参与开源项目6.加入Python社区7.利用资源学习8.制定学习计划9.持之以恒总结 如何系统地自学Python&#xff1f; 作为一个Python语…

Maxwell - 增量数据同步工具

前言 今天来学习一个新的大数据小工具 Maxwell &#xff0c;它和 Sqoop 很像。Sqoop主要用于在 Hadoop &#xff08;比如 HDFS、Hive、HBase 等&#xff09;和关系型数据库之间进行数据的批量导入和导出&#xff0c;而 Maxwell 则主要用于监控数据库的变化&#xff08;通过监控…

开发一款招聘小程序需要具备哪些功能?

随着时代的发展&#xff0c;找工作的方式也在不断变得简单&#xff0c;去劳务市场、人才市场的方式早就已经过时了&#xff0c;现在大多数年轻人都是直接通过手机来找工作。图片 找工作类的平台不但能扩大企业的招聘渠道&#xff0c;还能节省招聘的成本&#xff0c;方便求职者进…

Springboot项目的run debug都是灰色解决方法

IDEA下新建SpringBoot项目后&#xff0c;问题显示如下&#xff1a; 解决方法如下&#xff1a; 这个问题是由于缺少Configuration构建器的原因&#xff0c;因此&#xff1a; 1.点击Add Configuration 添加Spring Boot构建器&#xff0c;启动类选择好&#xff0c;点击确认即可&a…

Runtime Error while Saving a PyTorch bin Model: “File /** Cannot Be Opened“

原始保存代码为&#xff1a; quant_path "baichuan2_awq" torch.save(model.state_dict(), quant_path)报错如下&#xff1a; RuntimeError: File baichuan2_awq cannot be opened解决方法&#xff1a;需要保存的文件名字为"pytorch_model.bin" import…

Word docx文件重命名为zip文件,解压后直接查看和编辑

一个不知道算不算冷的知识[doge]&#xff1a; docx格式的文件本质上是一个ZIP文件 当把一个.docx文件重命名为.zip文件并解压后&#xff0c;你会发现里面包含了一些XML文件和媒体文件&#xff0c;它们共同构成了Word文档的内容和格式。 例如&#xff0c;word/document.xml文件…

Rust Vs Go:从头构建一个web服务

Go 和 Rust 之间的许多比较都强调它们在语法和初始学习曲线上的差异。然而&#xff0c;最终的决定性因素是重要项目的易用性。 “Rust 与 Go”争论 Rust vs Go 是一个不断出现的话题&#xff0c;并且已经有很多关于它的文章。部分原因是开发人员正在寻找信息来帮助他们决定下…

箱形理论在交易策略中的实战应用与优化

箱形理论&#xff0c;简单来说&#xff0c;就是将价格波动分成一段一段的方框&#xff0c;研究这些方框的高点和低点&#xff0c;来推测价格的趋势。 在上升行情中&#xff0c;价格每突破新高价后&#xff0c;由于群众惧高心理&#xff0c;可能会回跌一段&#xff0c;然后再上升…

HAL库 CubeMX STM32采用SDIO实现对SD卡和NAND Flash的读写

目录 完整项目源代码下载地址&#xff1a;HAL库CubeMX STM32采用SDIO实现对SD卡和NAND Flash的读写资源-CSDN文库 一、选择合适的存储芯片。 可以去雷龙官网白嫖&#xff0c;白嫖链接&#xff1a;免费样品 二、SD卡/SD NAND底层原理 三、硬件设计 1、SD NAND引脚图 2、芯片外观…

【4.3计算机网络】网络规划与设计

目录 1.网络规划2.逻辑网络设计3.物理网络设计 1.网络规划 需求分析->通信规范分析->逻辑网络设计->物理网络设计->实施阶段 2.逻辑网络设计 3.物理网络设计 例题1&#xff1a; 解析&#xff1a;选A。 例题2&#xff1a; 解析&#xff1a;选A。 例题3. 解析&am…

【数据库】哪些操作会导致索引失效

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 在数据库管理中&#xff0c;索引的有效性对于查询性能至关重要。然而&#xff0c;索引可能会因为各种操…

14. UE5 RPG使用GameplayTag

GameplayTag本来是应用在GAS游戏技能系统里面的&#xff0c;后来UE直接将其抽离出来&#xff0c;作为一个模块&#xff0c;现在可以不在GAS里也可以使用这个模块。比如&#xff0c;我需要判断一个射线拾取的物体&#xff0c;首先我需要判断这个actor是否存在&#xff0c;然后判…

Sora了解资料

一、基本介绍 1.1sora 在 2024 年 2 月 16 日&#xff0c;Open AI 宣布推出全新的生成式人工智能模型“Sora”。据了解&#xff0c;通过文本指令&#xff0c;Sora 可以直接输出长达 60 秒的视频&#xff0c;并且包含高度细致的背景、复杂的多角度镜头&#xff0c;以及富有情感…

Spring中常见的注解

1 spring注解介绍 Spring Framework是一个开源的Java平台&#xff0c;广泛用于创建高性能的企业应用程序。随着Spring的发展&#xff0c;注解&#xff08;Annotation&#xff09;已经成为了配置Spring应用程序的主要方式&#xff0c;逐渐取代了传统的XML配置。使用注解可以使代…
推荐文章