设计模式二十二:策略模式(Strategy Pattern)
定义一系列算法,将每个算法封装成独立的对象,并使这些对象可互相替换。这使得在运行时可以动态地选择算法,而不必改变使用算法的客户端代码。策略模式的主要目标是将算法的定义与使用分离,使得客户端可以根据需要灵活地选择和切换不同的算法,而不影响到客户端代码的稳定性。
策略模式的使用场景
- 多种算法实现:
当一个问题有多种算法实现时,可以使用策略模式来将这些算法封装成独立的策略类,使得这些算法可以互相替换,而不影响客户端代码。 - 避免条件判断:
当存在大量的条件语句来选择不同的行为时,可以使用策略模式将这些行为封装成策略类,从而减少条件判断,提高代码的可读性和可维护性。 - 算法变化频繁:
如果系统中的算法经常需要变化,使用策略模式可以方便地新增、修改和替换算法,而不必修改客户端代码。 - 开闭原则支持:
策略模式支持开闭原则,可以在不修改已有代码的情况下扩展系统功能。 - 分层架构:
在分层架构中,策略模式可以用于将业务逻辑与具体的实现分离,使得业务逻辑层和具体实现层解耦。 - 配置灵活性:
当需要根据配置文件或用户输入来选择不同的行为时,策略模式可以提供灵活的配置方式。 - 测试和维护性:
由于策略模式将不同的算法分离成独立的策略类,可以更方便地进行单元测试和维护。
策略模式主要角色
- 策略接口
定义了一组算法的共同接口,具体策略类需要实现这个接口。它通常包含一个或多个抽象方法,用于定义不同算法的行为。 - 具体策略类
实现了策略接口,即具体的算法逻辑。每个具体策略类负责实现一个特定的算法。具体策略类之间是可以相互替换的,客户端代码不需要知道具体算法的实现细节。 - 上下文
持有一个策略对象,并在需要时调用策略的方法。上下文将算法的执行委托给具体的策略对象。上下文也可以包含一些辅助方法,用于操作策略对象。
策略模式的流程
- 客户端创建一个上下文对象,并设置具体的策略对象。
- 当客户端需要执行特定算法时,它调用上下文的方法,上下文会将请求委托给具体策略对象
- 具体策略对象执行算法,并将结果返回给上下文,上下文将结果传递给客户端。
策略模式java代码示例
实现一生鲜市场到点打折活动
策略接口
// 策略接口
public interface DiscountStrategy {double applyDiscount(double originalPrice);
}
策略实现类
public class RegularDiscount implements DiscountStrategy{@Overridepublic double applyDiscount(double originalPrice) {return originalPrice;//原价}
}public class SaleDiscount implements DiscountStrategy {@Overridepublic double applyDiscount(double originalPrice) {return originalPrice*0.8;//8折}
}public class SpecialDiscount implements DiscountStrategy{@Overridepublic double applyDiscount(double originalPrice) {return originalPrice*0.5;//5折}
}
上下文
// 上下文类
public class ShoppingCart{private DiscountStrategy discountStrategy;public void setDiscountStrategy(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}//获取最新价格public double getPrice(double regularPrice){return discountStrategy.applyDiscount(regularPrice);}}
客户端
public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();double originalPrice = 100.0;double discountedPrice;cart.setDiscountStrategy(new RegularDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("8点价格:"+discountedPrice);cart.setDiscountStrategy(new SaleDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("9点价格:"+discountedPrice);cart.setDiscountStrategy(new SpecialDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("10点价格:"+discountedPrice);
}
输出
8点价格:100.0
9点价格:80.0
10点价格:50.0
策略模式优缺点
优点:
- 灵活性高: 策略模式使得算法可以独立地变化,而不会影响到客户端代码。可以随时切换或扩展算法,而无需修改客户端。
- 可维护性好: 每个具体策略类都具备清晰的职责,使得代码更加模块化和可读。新增或修改算法时,只需修改相应的策略类,不影响其他部分
- 遵循开闭原则: 策略模式支持开闭原则,可以在不修改已有代码的情况下添加新的策略类
- 消除条件判断: 策略模式可以避免大量的条件判断,将不同的行为封装到不同的策略类中,使得代码更加简洁
- 可测试性强: 每个策略类都是相对独立的,易于进行单元测试。
缺点:
- 类数量增多: 策略模式会引入多个具体策略类,可能导致类的数量增多,增加了代码的复杂度。
- 客户端需要了解策略: 客户端需要了解不同的策略类,并选择适当的策略,这可能在某些情况下增加了客户端的复杂度
- 增加对象数量: 每个策略类都是一个对象,可能会增加系统的对象数量。在某些情况下,可以通过共享策略对象来缓解这个问题
- 上下文类复杂: 上下文类需要持有一个策略对象,并在运行时选择合适的策略。在某些情况下,可能会使上下文类变得复杂
相关文章:
设计模式二十二:策略模式(Strategy Pattern)
定义一系列算法,将每个算法封装成独立的对象,并使这些对象可互相替换。这使得在运行时可以动态地选择算法,而不必改变使用算法的客户端代码。策略模式的主要目标是将算法的定义与使用分离,使得客户端可以根据需要灵活地选择和切换…...
【c语言】结构体内存对齐,位段,枚举,联合
之前学完结构体,有没有对结构体的大小会很疑惑呢??其实结构体在内存中存储时会存在内存对齐,捎带讲讲位段,枚举,和联合,跟着小张一起学习吧 结构体内存对齐 结构体的对齐规则: 第一个成员在与结…...
干货丨软件测试行业迎来新时代,AI将成为主流技术?
随着科技日新月异的发展,人工智能正逐渐渗透到我们生活的各方各面,从智能语音助手到自动驾驶汽车、从智能家居到人脸识别技术,AI正以其卓越的智能和学习能力引领着新时代的发展方向。 在这个快速演进的时代中,软件测试领域也受到了…...
MacOS goland go1.21 debug问题
安装dlv brew install dlv 安装之后在终端会显示所在目录 类似/usr/local/Cellar/delve/1.21.0/bin 配置goland 在文件系统中找到goland 右击选择show package contents -> Contents -> plugins -> go 尝试替换 其中对应系统 的 dlv 结果还是不行 然后打开应用gol…...
python 笔记(1)——基础和常用部分
目录 1、print 输出不换行 2、格式化输出字符串 3、浮点数的处理 4、进制转换和ASCII与字符间的转换 5、随机数 6、字符串截取和内置方法 6-1)字符串截取 6-2)字符串内置方法 7、元组、列表,及其遍历方式 7-1)列表常用内…...
kafka架构和原理详解
Apache Kafka 是一个分布式流数据平台,用于高吞吐量、持久性、可扩展的发布和订阅消息。它具有高度的可靠性,被广泛用于构建实时数据流处理、日志收集和数据管道等应用。 基本架构 1. 主题(Topic): 主题是消息的逻辑分类生产者将消息发布到特定的主题中,而消费者可以订阅…...
wsl Ubuntu中非root的普通用户怎么直接执行docker命令
docker需要root权限,如果希望非root用户直接使用docker命令,而不是使用sudo,可以选择将该用户加入到docker用户组。 sudo groupadd docker:添加到groupadd用户组(已经有docker用户组,所以可以不用再新增do…...
Web开发模式、API接口、restful规范、序列化和反序列化、drf安装和快速使用、路由转换器(复习)
一 Web开发模式 1. 前后端混合开发模式 前后端混合开发模式是一种开发方式,将前端和后端的开发工作结合在一起,以加快项目的开发速度和 提高协作效率。这种模式通常用于快速原型开发、小型项目或敏捷开发中。在前后端混合开发模式中,前端和…...
<AMBA总线篇> AXI总线协议介绍
目录 01 AXI协议简介 AXI协议特性 AXI协议传输特性 02 AXI协议架构 AXI协议架构 write transaction(写传输) read tramsaction(读传输) Interface and interconnect 典型的AXI系统拓扑 03 文章总结 大家好,这里是程序员杰克。一名平平无奇的嵌入式软件工程…...
一个简单的Python网络爬虫教程
网络爬虫是一种自动获取网页内容的程序,它可以从互联网上的网站中提取数据并进行分析。本教程将带您逐步了解如何使用 Python 构建一个简单的网络爬虫。 注意:在进行网络爬虫时,请遵守网站的使用条款和法律法规,避免对目标网站造…...
YARN资源管理框架论述
一、简介 为了实现一个Hadoop集群的集群共享、可伸缩性和可靠性,并消除早期MapReduce框架中的JobTracker性能瓶颈,开源社区引入了统一的资源管理框架YARN。 YARN是将JobTracker的两个主要功能(资源管理和作业调度/监控)分离&…...
Unity查找资源依赖关系
这个方法主要是发现资源乱用的情况,对应的逻辑可能要改一个才能用到自己的项目里面 [MenuItem("Tools/Prefab/查找选中资源依赖关系", false, 0)] public static void FindDependencies() { foreach (var guid in Selection.assetGUIDs…...
【操作系统】聊聊局部性原理是如何提升性能的
对于目前数据主导的系统,大多数都是Java/Go 技术栈MySQL,但是随着时间的推移,数据库数据的数据量过多,并且会频繁访问热点数据,为了提升系统的性能,一般都是加入缓存中间件、Redis。 局部性原理 我们知道…...
多线程应用——单例模式
单例模式 文章目录 单例模式一.什么是单例模式二.如何实现1.口头实现2.利用语法特性 三.实现方式(饿汉式懒汉式)1.饿汉式2.懒汉式3.线程安全的单例模式4.双重检查锁5.禁止指令重排序 一.什么是单例模式 单例模式(Singleton Patternÿ…...
几种在JavaScript中创建对象的方式!
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 字面量方式⭐ 构造函数方式⭐ Object.create()方式⭐ 工厂函数方式⭐ ES6类方式⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门…...
java项目mysql转postgresql
特殊函数 : mysql: find_in_set(?, ancestors) postgresql: ? ANY (string_to_array(ancestors,,)) mysql: date_format(t1.oper_time, %Y-%m-%d) postgresql: rksj::date to_char(inDate,YYYY-MM-DD) mysql&am…...
SpringBoot Mybatis 多数据源 MySQL+Oracle
一、背景 在SpringBoot Mybatis 项目中,需要连接 多个数据源,连接多个数据库,需要连接一个MySQL数据库和一个Oracle数据库 二、依赖 pom.xml <dependencies><dependency><groupId>org.springframework.boot</groupId&…...
(笔记五)利用opencv进行图像几何转换
参考网站:https://docs.opencv.org/4.1.1/da/d6e/tutorial_py_geometric_transformations.html (1)读取原始图像和标记图像 import cv2 as cv import numpy as np from matplotlib import pyplot as pltpath r"D:\data\flower.jpg&qu…...
【Flutter】Flutter 使用 fluttertoast 实现显示 Toast 消息
【Flutter】Flutter 使用 fluttertoast 实现显示 Toast 消息 文章目录 一、前言二、安装和基础使用三、不同平台的支持情况四、如何自定义 Toast五、在实际业务中的应用六、完整的业务代码示例(基于 Web 端)七、总结 一、前言 在这篇文章中,…...
nowcoder NC236题 最大差值
目录 题目描述: 示例1 示例2 题干解析: 暴力求解: 代码展示: 优化: 代码展示: 题目跳转https://www.nowcoder.com/practice/a01abbdc52ba4d5f8777fb5dae91b204?tpId128&tqId33768&ru/exa…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...
零基础在实践中学习网络安全-皮卡丘靶场(第十一期-目录遍历模块)
经过前面几期的内容我们学习了很多网络安全的知识,而这期内容就涉及到了前面的第六期-RCE模块,第七期-File inclusion模块,第八期-Unsafe Filedownload模块。 什么是"遍历"呢:对学过一些开发语言的朋友来说应该知道&…...
