【设计模式】行为型设计模式之 策略模式学习实践
介绍
策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们
使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的
解法可能有多种;再⽐如商场的打折促销活动,打折⽅案也有很多种,有些商品是不参与折扣活
动要按照原价销售,有些商品打8.5折,有些打6折,有些是返现5元等。
优缺点和场景
优点
- 完美符合开闭原则,可以再不修改原系统基础上选择算法行为,或者新增新的算法。
- 策略模式,将一类算法进行了抽象,可以将公共部分进行抽离。避免重复代码。
- 策略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。提供了可替换继承关系的办法,如果不用策略模式,那么环境类,可能自己就有多个子类了,算法和算法的使用还在一起,那就不符合开闭原则。
- 可以避免多重条件选择语句。
- 算法抽离后,更方便不同的环境类复用。
缺点
- 客户端必须知道所有的策略类,并且决定使用哪一个。
- 造成了很多具体的策略的类,细小的变化都需要增加新的具体策略类。
使用场景
- 系统需要动态的在某些算法里进行选择,那么使用策略模式,用户只要维持一个算法的抽象类对象即可。
- 一个对象有很多的行为,避免在一个类里,根据不同的条件进行多重条件判断时。(if(a) 行为a if(b)行为b 将a和b拆成两个具体类。) 可以使用策略模式,将不同的行为,抽象成具体的策略类。
- 需要将具体的算法实现,和使用者进行解耦,提高算法的保密性和安全性。
结构
略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。使用算法的上下文环境类中,针对抽象的策略类进行编程。符合依赖倒转原则,并且出现了新的算法时,只需要增加一个新的实现即可。
- **策略(Strategy) **定义所有⽀持算法的公共接⼝。 Context 使⽤这个接⼝来调⽤某 ConcreteStrategy 定义的算法。
- **策略实现(ConcreteStrategy) **实现了Strategy 接⼝的具体算法
- **上下⽂环境(Context) **维护⼀个 Strategy 对象的引⽤,⽤⼀个 ConcreteStrategy 对象来装配可定义⼀个接⼝⽅法让 Strategy 访问它的数据
UML类图
基础案例
针对不同商品的打折算法,在引入策略模式前,由一个算法类的方法维护,包含大量的条件转移,并且也不利于维护。
代码下载:strategy.zip
引入策略模式前
引入策略模式前,不同的打折算法的计算过程存在的问题。
- 有多重条件选择语句,代码混乱
- 不同的算法没有办法进行在别处复用
- 新增算法的话,需要修改原来的代码,不符合开闭原则。
package behavioralPattern.strategy;import java.text.MessageFormat;/*** 引入策略模式前,不同的打折算法的计算过程* 1.有多重条件选择语句,代码混乱* 2.不同的算法没有办法进行在别处复用* 3.新增算法的话,需要修改原来的代码,不符合开闭原则。** @author liuyp* @date 2022/09/25*/
public class BuyGoods {private String goods;private double price;private double finalPrice;private String desc;public BuyGoods(String goods, double price) {this.goods = goods;this.price = price;}public double calculate(String discountType) {if ("discount85".equals(discountType)) {finalPrice = price * 0.85;desc = "该商品可享受8.5折优惠";} else if ("discount6".equals(discountType)) {finalPrice = price * 0.6;desc = "该商品可享受6折优惠";} else if ("return5".equals(discountType)) {finalPrice = price >= 5 ? price - 5 : 0;desc = "该商品可返现5元";} else {finalPrice = price;desc = "对不起,该商品不参与优惠活动";}System.out.println(MessageFormat.format("您购买的商品为:{0},原价为: {1},{2},最终售卖价格为:{3}", goods, price, desc, finalPrice));return finalPrice;}
}
引入策略模式
修改步骤
- 策略: 引入抽象类,所有的价格计算算法实现该抽象类。
- 策略实现:针对原有的if else中的价格计算算法,分别在一个个具体的策略实现类中进行实现。
- 环境类:购买商品的类中,只需要维护一个策略抽象类的引用即可,传入不通风策略实现,即可实现不同的打折策略。
抽象打折策略
/*** 策略模式中,对策略的抽象层。* 抽象出了公共的描述、价格属性。* 定义了需要子类实现的,具体的打折策略方法。** @author StoneYu* @date 2022/09/25*/
public abstract class AbstractDiscount {protected double finalPrice;protected String desc;public AbstractDiscount(String desc) {this.desc = desc;}public double getFinalPrice() {return finalPrice;}public void setFinalPrice(double finalPrice) {this.finalPrice = finalPrice;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public abstract double discount(double price);
}
拆分各个打折策略的实现
public class Discount6 extends AbstractDiscount {public Discount6() {super("该商品可享受6折优惠");}@Overridepublic double discount(double price) {finalPrice = price * 0.6;return finalPrice;}
}public class Discount85 extends AbstractDiscount {public Discount85() {super("该商品可享受8.5折优惠");}@Overridepublic double discount(double price) {finalPrice = price * 0.85;return finalPrice;}
}public class NoDiscount extends AbstractDiscount {public NoDiscount() {super("对不起,该商品不参与优惠活动");}@Overridepublic double discount(double price) {finalPrice = price;return finalPrice;}
}public class Return5 extends AbstractDiscount {public Return5() {super("该商品可返现5元");}@Overridepublic double discount(double price) {this.finalPrice = price >= 5 ? price - 5 : 0;return finalPrice;}
}
修改环境类,只需要维护策略的引用
/*** 策略模式-环境类* 使用策略模式优化后的购买商品的方法* 1.没有了各种if-else* 2.不需要关注算法的具体实现,只需要维护一个策略的抽象类引用。符合依赖倒转原则** @author StoneYu* @date 2022/09/25*/
public class BuyGoods {private String goods;private double price;private AbstractDiscount abstractDiscount;public BuyGoods(String goods, double price, AbstractDiscountabstractDiscount) {this.goods = goods;this.price = price;this.abstractDiscount = abstractDiscount;}public double calculate() {double finalPrice = abstractDiscount.discount(this.price);String desc = abstractDiscount.getDesc();System.out.println(MessageFormat.format("商品:{0},原价:{1},{2},最 终价格为:{3}", goods, price, desc, finalPrice));return finalPrice;}
}
Spring中实践
新建策略接口
public interface DiscountStratege {/*** 折扣方法*/void discount();}
具体的策略 1
/*** 具体策略实现1** @author LiuYuping* @date 2024/03/14 15:14*/
@Component
public class FullReductionDiscountStratege implements DiscountStratege{@Overridepublic void discount() {System.out.println("满减策略,满一百减100");}
}
具体策略 2
/*** 具体策略实现2** @author LiuYuping* @date 2024/03/14 15:15*/
@Component
public class WeekDayDiscountStratege implements DiscountStratege{@Overridepublic void discount() {System.out.println("这里是周末满减策略");}
}
策略枚举,保存所有策略名称
public enum DiscountStrategeEnum {WEEK_DAY_STRATEGE("fullReductionDiscountStratege","满一百减一百"),FULL_REDUCTION("weekDayDiscountStratege","周末满减策略");String concernedStrategeBeanId;String strategeName;DiscountStrategeEnum(String concernedStrategeBeanId, String strategeName) {this.concernedStrategeBeanId = concernedStrategeBeanId;this.strategeName = strategeName;}public String getConcernedStrategeBeanId() {return concernedStrategeBeanId;}public String getStrategeName() {return strategeName;}
}
策略 Context 保存所有策略 Bean 示例
@Service
public class DiscountStrategeContext {@Autowiredprivate Map<String,DiscountStratege> allDiscountStrategeMap;/*** 获取指定的策略** @param discountStrategeEnum 折扣策略枚举* @return {@link DiscountStratege}*/public DiscountStratege getStratege(DiscountStrategeEnum discountStrategeEnum){return allDiscountStrategeMap.get(discountStrategeEnum.getConcernedStrategeBeanId());}}
用例
在需要使用策略的地方,按需注入指定类型的策略对象,新增策略时不需要修改原有代码
@SpringBootTest
class DemoApplicationTests {@AutowiredDiscountStrategeContext discountStrategeContext;@Testvoid testDiscountStratege() {DiscountStratege stratege = discountStrategeContext.getStratege(DiscountStrategeEnum.WEEK_DAY_STRATEGE);stratege.discount();}}
相关文章:

【设计模式】行为型设计模式之 策略模式学习实践
介绍 策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们 使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的 解法可能有…...
lua中大数相乘的问题
math.maxinteger * 2 --> -2 原因:math.maxinteger的二进制 : 0111111111111111111111111111111111111111111111111111111111111111 往左移位,最右加一个0,是 1111111111111111111111111111111111111111111111111111111111111…...

第一个SpringBoot项目
目录 💭1、新建New Project IDEA2023版本创建Sping项目只能勾选17和21,却无法使用Java8?🌟 2、下载JDK 17🌟 💭2、项目创建成功界面 1、目录 🌟 2、pom文件🌟 💭3、…...
Android 10.0 Launcher修改density禁止布局改变功能实现
1.前言 在10.0的系统rom定制化开发中,在关于Launcher3的定制化功能中,在有些功能需要要求改变系统原有的density屏幕密度, 这样就会造成Launcher3的布局变化,所以就不符合要求,接下来就来看下如何禁止改变density造成Launcher3布局功能 改变的实现 2.Launcher修改densit…...

CAN协议简介
协议简介 can协议是一种用于控制网络的通信协议。它是一种基于广播的多主机总线网络协议,常用于工业自动化和控制领域。can协议具有高可靠性、实时性强和抗干扰能力强的特点,被广泛应用于汽车、机械、航空等领域。 can协议采用了先进的冲突检测和错误检测…...

(二)JSX基础
什么是JSX 概念:JSX是JavaScript和XML(HTML)的缩写,表示在JS代码中编写HTML模版结构,它是React中编写UI模板的方式。 优势:1.HTML的声明式模版方法;2.JS的可编程能力 JSX的本质 JSX并不是标准…...
GB 38469-2019 船舶涂料中有害物质限量检测
船舶涂料是指涂于船舶各部位,能防止海水、海洋大气腐蚀和海生物附着及满足船舶特种要求的各种涂料的统称。 GB 38469-2019船舶涂料中有害物质限量检测项目: 测试指标 测试方法 挥发性有机化合物VOC GB 30981 甲苯 GB 24408 苯 GB 30981 甲醇 G…...

汇编:数组-寻址取数据
比例因子寻址: 比例因子寻址(也称为比例缩放索引寻址或基址加变址加比例因子寻址)是一种复杂的内存寻址方式,常用于数组和指针操作。它允许通过一个基址寄存器、一个变址寄存器和一个比例因子来计算内存地址。 语法 比例因子寻…...
ROS自带的OpenCV库和自己安装版本冲突问题现象及解决方法
文章目录 1. 问题现象1.1 编译过程警告1.2 程序运行报错 2. 分析问题原因3. 解决方法 1. 问题现象 1.1 编译过程警告 warning: lipopencv_improc.so.406, needed by /usr/local/lib/libopencv_xfeatures2d.so.4.6.0, may conflict with libopencv_imgproc.so.4.21.2 程序运行…...

html+CSS+js部分基础运用19
1. 应用动态props传递数据,输出影片的图片、名称和描述等信息【要求使用props】,效果图如下: 2.在页面中定义一个按钮和一行文本,通过单击按钮实现放大文本的功能。【要求使用$emit()】 代码可以截图或者复制黏贴放置在“实验…...
探索 Debian 常用命令:掌握 Linux 系统管理的重要一步
Debian 作为一个稳定、高效和安全的操作系统,广泛应用于服务器、桌面和嵌入式系统中。对于新手和经验丰富的系统管理员来说,熟练掌握 Debian 的常用命令是管理和维护系统的基础。本文将详细介绍一些在 Debian 系统中经常使用的命令,帮助读者更好地理解和操作这个强大的操作系…...
「C系列」C 作用域规则
文章目录 一、C 作用域规则二、案例1. 块作用域(Block Scope)2. 文件作用域(File Scope)3. 静态作用域(Static Scope)静态局部变量静态全局变量 4. 函数参数的作用域5. 结构体和联合体的作用域 三、相关链接…...

【机器学习基础】Python编程10:五个实用练习题的解析与总结
Python是一种广泛使用的高级编程语言,它在机器学习领域中的重要性主要体现在以下几个方面: 简洁易学:Python语法简洁清晰,易于学习,使得初学者能够快速上手机器学习项目。 丰富的库支持:Python拥有大量的机…...
【设计模式】结构型设计模式之 门面模式
介绍 门面模式(Facade Pattern)是一种常用的设计模式,属于结构型模式的范畴。它为子系统中的一系列接口提供一个简化的统一接口,即一个外观(Facade),从而使子系统更加容易使用。门面模式并不修…...
MAC地址简介
一、MAC和ip地址 很多同学只知道ip地址,同时也知道ip在网络通讯中的重要性,实际上要实现网络通信的话,除了ip地址外还需要MAC地址的配合,只有在这两种地址的配合之下才能完整的实现互联网的通信。但是由于MAC地址的使用࿰…...
五种网络IO模型
目录 前言 文件描述符 为什么要多种io模型 同步IO 1.阻塞IO 2.非阻塞IO 3.多路复用IO(事件驱动IO) select: poll: epoll: 4.信号驱动IO 异步IO 区别 前言 文件描述符 首先我们了解一下文件描述符是什么:…...

VSCode超过390万下载的请求插件
Thunder Client 是一款在 VSCode(Visual Studio Code)中非常受欢迎的 REST API 客户端插件,由Ranga Vadhineni开发,现在已经有超过390万的下载量。它允许开发者直接在编辑器内发送 HTTP 请求,查看响应。Thunder Client…...
前端 JS 经典:下载的流式传输
触发下载在浏览器中有两种方式:1. 客户端的方式 2. 服务器的方式 1. 服务器的方式 通过 a 元素链接到一个服务器的地址,然后需要后端人员配置,当用户点击按钮请求这个地址时,服务端给他加上一个响应头。Content-Disposition 设置…...

k8s面试题大全,保姆级的攻略哦(三)
目录 1、简述ETCD及其特点? 2、简述ETCD适应的场景? 3、简述什么是Kubernetes? 4、简述Kubernetes和Docker的关系? 5、简述Kubernetes中什么是Minikube、Kubectl、Kubelet? 6、简述Kubernetes常见的部署方式? 7、简述Kubernetes如何实现集群管理? 8、简述Kubern…...

从年金理论到杠杆效应,再到财务报表与投资评估指标
一、解释普通年金终值和普通年金现值的概念。 普通年金终值:以利率为1%,每期收款100元,5期为例,普通年金终值的折算过程如图: 普通年金现值:以利率为1%,每期收款100元,5期为例&am…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...