【设计模式】行为型设计模式之 策略模式学习实践
介绍
策略模式(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…...
BGE-Reranker-v2-m3为何必须用?RAG幻觉过滤入门必看
BGE-Reranker-v2-m3为何必须用?RAG幻觉过滤入门必看 如果你正在搭建RAG系统,或者已经搭建了但总觉得回答质量时好时坏,经常出现“幻觉”——也就是模型一本正经地胡说八道——那你很可能遇到了一个核心问题:向量检索“搜不准”。…...
PyTorch 2.8镜像部署教程:RTX 4090D配置htop实时监控GPU/CPU/内存使用
PyTorch 2.8镜像部署教程:RTX 4090D配置htop实时监控GPU/CPU/内存使用 1. 环境准备与快速部署 在开始之前,请确保您的硬件配置满足以下要求: 显卡:RTX 4090D 24GB显存内存:120GB及以上存储:系统盘50GB …...
Ostrakon-VL-8B零售AI创新:用像素游戏化设计提升一线员工使用意愿
Ostrakon-VL-8B零售AI创新:用像素游戏化设计提升一线员工使用意愿 1. 项目背景与设计理念 在零售和餐饮行业,一线员工使用AI工具的意愿往往不高。传统工业级UI界面过于复杂,操作流程繁琐,导致员工抵触新技术。Ostrakon-VL-8B团队…...
Matlab源代码教程:枝晶生长模拟中的溶质与液相分数分析
枝晶生长模拟,溶质、液相分数,matlab源代码 教程相场法模拟枝晶生长这事挺有意思的——想象金属熔液凝固时,那些像雪花般绽放的晶体结构,背后其实是溶质扩散和相变的战场。今儿咱们用MATLAB整活,搞个能看见晶体长毛刺的…...
3DGS训练完模型怎么可视化?手把手教你用官方Viewer在Windows上查看结果
3DGS训练完模型怎么可视化?手把手教你用官方Viewer在Windows上查看结果 当你花费数小时甚至数天时间在Linux服务器上完成3D高斯泼溅(3DGS)模型的训练后,最令人兴奋的时刻莫过于亲眼看到自己的训练成果。本文将详细介绍如何将训练好的模型从Linux服务器迁…...
mbed OS双极性步进电机驱动库设计与应用
1. 项目概述BipoarStepperMotor 是一个面向 ARM Cortex-M 系统、专为 mbed OS 平台设计的双极性步进电机驱动库。该库不依赖特定硬件抽象层(HAL)变体,而是基于 mbed OS 提供的标准 DigitalOut 和 PwmOut 接口构建,具备良好的跨平台…...
3分钟掌握哔哩下载姬:零安装B站视频下载神器使用指南
3分钟掌握哔哩下载姬:零安装B站视频下载神器使用指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&#x…...
不止基础管理!国产 CRM 软件如何用数据分析赋能客户与销售工作
引言2026年国内企业数字化转型已进入深水区,CRM早已脱离了单纯的客户信息台账工具属性,数据分析能力成为衡量CRM产品价值的核心指标——从线索获客成本核算到跟单转化率优化,从客户复购价值挖掘到全链路风险管控,高质量的数据分析…...
5步高效使用小说下载工具:零基础也能掌握的开源项目全攻略
5步高效使用小说下载工具:零基础也能掌握的开源项目全攻略 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 在数字阅读时代,拥有一款可靠的小说下载工具能让你…...
别再手动调了!用Visio这个隐藏的字体设置窗口,一键切换泳道图标题横竖排
Visio高效技巧:解锁泳道图标题排版的隐藏技能 每次在Visio中调整泳道图标题方向时,你是否还在反复右键点击、寻找格式选项?其实Visio内置了一个被多数用户忽略的高效设置窗口——"字体"对话框。这个看似普通的设置面板,…...
