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

【设计模式】行为型设计模式之 策略模式学习实践

介绍

策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们
使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的
解法可能有多种;再⽐如商场的打折促销活动,打折⽅案也有很多种,有些商品是不参与折扣活
动要按照原价销售,有些商品打8.5折,有些打6折,有些是返现5元等。

优缺点和场景

优点

  1. 完美符合开闭原则,可以再不修改原系统基础上选择算法行为,或者新增新的算法。
  2. 策略模式,将一类算法进行了抽象,可以将公共部分进行抽离。避免重复代码。
  3. 策略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。提供了可替换继承关系的办法,如果不用策略模式,那么环境类,可能自己就有多个子类了,算法和算法的使用还在一起,那就不符合开闭原则。
  4. 可以避免多重条件选择语句。
  5. 算法抽离后,更方便不同的环境类复用。

缺点

  1. 客户端必须知道所有的策略类,并且决定使用哪一个。
  2. 造成了很多具体的策略的类,细小的变化都需要增加新的具体策略类。

使用场景

  1. 系统需要动态的在某些算法里进行选择,那么使用策略模式,用户只要维持一个算法的抽象类对象即可。
  2. 一个对象有很多的行为,避免在一个类里,根据不同的条件进行多重条件判断时。(if(a) 行为a if(b)行为b 将a和b拆成两个具体类。) 可以使用策略模式,将不同的行为,抽象成具体的策略类。
  3. 需要将具体的算法实现,和使用者进行解耦,提高算法的保密性和安全性。

结构

略模式对算法的封装,将算法的责任和算法本身分割开,交给不同的对象管理。使用算法的上下文环境类中,针对抽象的策略类进行编程。符合依赖倒转原则,并且出现了新的算法时,只需要增加一个新的实现即可。

  • **策略(Strategy) **定义所有⽀持算法的公共接⼝。 Context 使⽤这个接⼝来调⽤某 ConcreteStrategy 定义的算法。
  • **策略实现(ConcreteStrategy) **实现了Strategy 接⼝的具体算法
  • **上下⽂环境(Context) **维护⼀个 Strategy 对象的引⽤,⽤⼀个 ConcreteStrategy 对象来装配可定义⼀个接⼝⽅法让 Strategy 访问它的数据

UML类图

基础案例

针对不同商品的打折算法,在引入策略模式前,由一个算法类的方法维护,包含大量的条件转移,并且也不利于维护。
代码下载:strategy.zip

引入策略模式前

引入策略模式前,不同的打折算法的计算过程存在的问题。

  1. 有多重条件选择语句,代码混乱
  2. 不同的算法没有办法进行在别处复用
  3. 新增算法的话,需要修改原来的代码,不符合开闭原则。
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;}
}

引入策略模式

修改步骤

  1. 策略: 引入抽象类,所有的价格计算算法实现该抽象类。
  2. 策略实现:针对原有的if else中的价格计算算法,分别在一个个具体的策略实现类中进行实现。
  3. 环境类:购买商品的类中,只需要维护一个策略抽象类的引用即可,传入不通风策略实现,即可实现不同的打折策略。

抽象打折策略

/*** 策略模式中,对策略的抽象层。* 抽象出了公共的描述、价格属性。* 定义了需要子类实现的,具体的打折策略方法。** @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();}}

相关文章:

【设计模式】行为型设计模式之 策略模式学习实践

介绍 策略模式&#xff08;Strategy&#xff09;&#xff0c;就是⼀个问题有多种解决⽅案&#xff0c;选择其中的⼀种使⽤&#xff0c;这种情况下我们 使⽤策略模式来实现灵活地选择&#xff0c;也能够⽅便地增加新的解决⽅案。⽐如做数学题&#xff0c;⼀个问题的 解法可能有…...

lua中大数相乘的问题

math.maxinteger * 2 --> -2 原因&#xff1a;math.maxinteger的二进制 &#xff1a; 0111111111111111111111111111111111111111111111111111111111111111 往左移位&#xff0c;最右加一个0&#xff0c;是 1111111111111111111111111111111111111111111111111111111111111…...

第一个SpringBoot项目

目录 &#x1f4ad;1、新建New Project IDEA2023版本创建Sping项目只能勾选17和21&#xff0c;却无法使用Java8&#xff1f;&#x1f31f; 2、下载JDK 17&#x1f31f; &#x1f4ad;2、项目创建成功界面 1、目录 &#x1f31f; 2、pom文件&#x1f31f; &#x1f4ad;3、…...

Android 10.0 Launcher修改density禁止布局改变功能实现

1.前言 在10.0的系统rom定制化开发中,在关于Launcher3的定制化功能中,在有些功能需要要求改变系统原有的density屏幕密度, 这样就会造成Launcher3的布局变化,所以就不符合要求,接下来就来看下如何禁止改变density造成Launcher3布局功能 改变的实现 2.Launcher修改densit…...

CAN协议简介

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

(二)JSX基础

什么是JSX 概念&#xff1a;JSX是JavaScript和XML&#xff08;HTML&#xff09;的缩写&#xff0c;表示在JS代码中编写HTML模版结构&#xff0c;它是React中编写UI模板的方式。 优势&#xff1a;1.HTML的声明式模版方法&#xff1b;2.JS的可编程能力 JSX的本质 JSX并不是标准…...

GB 38469-2019 船舶涂料中有害物质限量检测

船舶涂料是指涂于船舶各部位&#xff0c;能防止海水、海洋大气腐蚀和海生物附着及满足船舶特种要求的各种涂料的统称。 GB 38469-2019船舶涂料中有害物质限量检测项目&#xff1a; 测试指标 测试方法 挥发性有机化合物VOC GB 30981 甲苯 GB 24408 苯 GB 30981 甲醇 G…...

汇编:数组-寻址取数据

比例因子寻址&#xff1a; 比例因子寻址&#xff08;也称为比例缩放索引寻址或基址加变址加比例因子寻址&#xff09;是一种复杂的内存寻址方式&#xff0c;常用于数组和指针操作。它允许通过一个基址寄存器、一个变址寄存器和一个比例因子来计算内存地址。 语法 比例因子寻…...

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传递数据&#xff0c;输出影片的图片、名称和描述等信息【要求使用props】&#xff0c;效果图如下&#xff1a; 2.在页面中定义一个按钮和一行文本&#xff0c;通过单击按钮实现放大文本的功能。【要求使用$emit()】 代码可以截图或者复制黏贴放置在“实验…...

探索 Debian 常用命令:掌握 Linux 系统管理的重要一步

Debian 作为一个稳定、高效和安全的操作系统,广泛应用于服务器、桌面和嵌入式系统中。对于新手和经验丰富的系统管理员来说,熟练掌握 Debian 的常用命令是管理和维护系统的基础。本文将详细介绍一些在 Debian 系统中经常使用的命令,帮助读者更好地理解和操作这个强大的操作系…...

「C系列」C 作用域规则

文章目录 一、C 作用域规则二、案例1. 块作用域&#xff08;Block Scope&#xff09;2. 文件作用域&#xff08;File Scope&#xff09;3. 静态作用域&#xff08;Static Scope&#xff09;静态局部变量静态全局变量 4. 函数参数的作用域5. 结构体和联合体的作用域 三、相关链接…...

【机器学习基础】Python编程10:五个实用练习题的解析与总结

Python是一种广泛使用的高级编程语言&#xff0c;它在机器学习领域中的重要性主要体现在以下几个方面&#xff1a; 简洁易学&#xff1a;Python语法简洁清晰&#xff0c;易于学习&#xff0c;使得初学者能够快速上手机器学习项目。 丰富的库支持&#xff1a;Python拥有大量的机…...

【设计模式】结构型设计模式之 门面模式

介绍 门面模式&#xff08;Facade Pattern&#xff09;是一种常用的设计模式&#xff0c;属于结构型模式的范畴。它为子系统中的一系列接口提供一个简化的统一接口&#xff0c;即一个外观&#xff08;Facade&#xff09;&#xff0c;从而使子系统更加容易使用。门面模式并不修…...

MAC地址简介

一、MAC和ip地址 很多同学只知道ip地址&#xff0c;同时也知道ip在网络通讯中的重要性&#xff0c;实际上要实现网络通信的话&#xff0c;除了ip地址外还需要MAC地址的配合&#xff0c;只有在这两种地址的配合之下才能完整的实现互联网的通信。但是由于MAC地址的使用&#xff0…...

五种网络IO模型

目录 前言 文件描述符 为什么要多种io模型 同步IO 1.阻塞IO 2.非阻塞IO 3.多路复用IO&#xff08;事件驱动IO&#xff09; select: poll&#xff1a; epoll&#xff1a; 4.信号驱动IO 异步IO 区别 前言 文件描述符 首先我们了解一下文件描述符是什么&#xff1a;…...

VSCode超过390万下载的请求插件

Thunder Client 是一款在 VSCode&#xff08;Visual Studio Code&#xff09;中非常受欢迎的 REST API 客户端插件&#xff0c;由Ranga Vadhineni开发&#xff0c;现在已经有超过390万的下载量。它允许开发者直接在编辑器内发送 HTTP 请求&#xff0c;查看响应。Thunder Client…...

前端 JS 经典:下载的流式传输

触发下载在浏览器中有两种方式&#xff1a;1. 客户端的方式 2. 服务器的方式 1. 服务器的方式 通过 a 元素链接到一个服务器的地址&#xff0c;然后需要后端人员配置&#xff0c;当用户点击按钮请求这个地址时&#xff0c;服务端给他加上一个响应头。Content-Disposition 设置…...

k8s面试题大全,保姆级的攻略哦(三)

目录 1、简述ETCD及其特点? 2、简述ETCD适应的场景? 3、简述什么是Kubernetes? 4、简述Kubernetes和Docker的关系? 5、简述Kubernetes中什么是Minikube、Kubectl、Kubelet? 6、简述Kubernetes常见的部署方式? 7、简述Kubernetes如何实现集群管理? 8、简述Kubern…...

从年金理论到杠杆效应,再到财务报表与投资评估指标

一、解释普通年金终值和普通年金现值的概念。 普通年金终值&#xff1a;以利率为1%&#xff0c;每期收款100元&#xff0c;5期为例&#xff0c;普通年金终值的折算过程如图&#xff1a; 普通年金现值&#xff1a;以利率为1%&#xff0c;每期收款100元&#xff0c;5期为例&am…...

BGE-Reranker-v2-m3为何必须用?RAG幻觉过滤入门必看

BGE-Reranker-v2-m3为何必须用&#xff1f;RAG幻觉过滤入门必看 如果你正在搭建RAG系统&#xff0c;或者已经搭建了但总觉得回答质量时好时坏&#xff0c;经常出现“幻觉”——也就是模型一本正经地胡说八道——那你很可能遇到了一个核心问题&#xff1a;向量检索“搜不准”。…...

PyTorch 2.8镜像部署教程:RTX 4090D配置htop实时监控GPU/CPU/内存使用

PyTorch 2.8镜像部署教程&#xff1a;RTX 4090D配置htop实时监控GPU/CPU/内存使用 1. 环境准备与快速部署 在开始之前&#xff0c;请确保您的硬件配置满足以下要求&#xff1a; 显卡&#xff1a;RTX 4090D 24GB显存内存&#xff1a;120GB及以上存储&#xff1a;系统盘50GB …...

Ostrakon-VL-8B零售AI创新:用像素游戏化设计提升一线员工使用意愿

Ostrakon-VL-8B零售AI创新&#xff1a;用像素游戏化设计提升一线员工使用意愿 1. 项目背景与设计理念 在零售和餐饮行业&#xff0c;一线员工使用AI工具的意愿往往不高。传统工业级UI界面过于复杂&#xff0c;操作流程繁琐&#xff0c;导致员工抵触新技术。Ostrakon-VL-8B团队…...

Matlab源代码教程:枝晶生长模拟中的溶质与液相分数分析

枝晶生长模拟&#xff0c;溶质、液相分数&#xff0c;matlab源代码 教程相场法模拟枝晶生长这事挺有意思的——想象金属熔液凝固时&#xff0c;那些像雪花般绽放的晶体结构&#xff0c;背后其实是溶质扩散和相变的战场。今儿咱们用MATLAB整活&#xff0c;搞个能看见晶体长毛刺的…...

3DGS训练完模型怎么可视化?手把手教你用官方Viewer在Windows上查看结果

3DGS训练完模型怎么可视化&#xff1f;手把手教你用官方Viewer在Windows上查看结果 当你花费数小时甚至数天时间在Linux服务器上完成3D高斯泼溅(3DGS)模型的训练后&#xff0c;最令人兴奋的时刻莫过于亲眼看到自己的训练成果。本文将详细介绍如何将训练好的模型从Linux服务器迁…...

mbed OS双极性步进电机驱动库设计与应用

1. 项目概述BipoarStepperMotor 是一个面向 ARM Cortex-M 系统、专为 mbed OS 平台设计的双极性步进电机驱动库。该库不依赖特定硬件抽象层&#xff08;HAL&#xff09;变体&#xff0c;而是基于 mbed OS 提供的标准 DigitalOut 和 PwmOut 接口构建&#xff0c;具备良好的跨平台…...

3分钟掌握哔哩下载姬:零安装B站视频下载神器使用指南

3分钟掌握哔哩下载姬&#xff1a;零安装B站视频下载神器使用指南 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#x…...

不止基础管理!国产 CRM 软件如何用数据分析赋能客户与销售工作

引言2026年国内企业数字化转型已进入深水区&#xff0c;CRM早已脱离了单纯的客户信息台账工具属性&#xff0c;数据分析能力成为衡量CRM产品价值的核心指标——从线索获客成本核算到跟单转化率优化&#xff0c;从客户复购价值挖掘到全链路风险管控&#xff0c;高质量的数据分析…...

5步高效使用小说下载工具:零基础也能掌握的开源项目全攻略

5步高效使用小说下载工具&#xff1a;零基础也能掌握的开源项目全攻略 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 在数字阅读时代&#xff0c;拥有一款可靠的小说下载工具能让你…...

别再手动调了!用Visio这个隐藏的字体设置窗口,一键切换泳道图标题横竖排

Visio高效技巧&#xff1a;解锁泳道图标题排版的隐藏技能 每次在Visio中调整泳道图标题方向时&#xff0c;你是否还在反复右键点击、寻找格式选项&#xff1f;其实Visio内置了一个被多数用户忽略的高效设置窗口——"字体"对话框。这个看似普通的设置面板&#xff0c;…...