Python策略模式介绍、使用方法
一、Python策略模式介绍
Python策略模式(Strategy Pattern)是一种软件设计模式,用于通过将算法封装为独立的对象,而使得它们可以在运行时动态地相互替换。该模式使得算法的变化独立于使用它们的客户端,从而达到代码的可扩展性、灵活性和可维护性。
功能:
1.将不同算法进行抽象和封装,使得它们可以互相替换,从而增强程序的可扩展性。
2.将算法的变化独立于客户端,使得客户端代码不需要修改即可使用不同的算法。
3.提高程序的可读性和可维护性。
优点:
1.代码可扩展性和灵活性好,能够适应不同的需求。
2.降低模块之间的耦合度,提高代码的可维护性和可读性。
3.具有良好的可扩展性,可以动态地增加、删除或替换算法。
缺点:
1.会增加一定的复杂度,需要额外的类定义。
2.可能会导致系统中出现较多的类,增加系统的复杂度。
3.需要客户端了解不同策略的差异,才能选择合适的策略。
应用场景:
1.需要在运行时根据不同情况选择不同算法的场景。
2.需要封装业务逻辑的场景。
3.需要对同一种算法进行多次修改的场景。
使用方式:
1.抽象出一个策略接口,定义策略的方法。
2.将不同的算法分别封装为具体的策略类,并实现策略接口的方法。
3.创建一个策略上下文类,负责调用不同的策略,根据不同的需求选择合适的策略。
在应用程序开发中的应用:
1.实现排序算法,将排序逻辑抽象出来,将不同的排序算法封装为不同的策略,然后在实现排序的过程中,动态地选择不同的排序算法。
2.实现搜索算法,将搜索算法封装为不同的策略,然后在实现搜索的过程中,动态地选择不同的搜索算法。
二、策略模式使用
工作原理:
1.抽象策略类:定义了一个公共接口,用于所有策略类的实现。
2.具体策略类:具体实现了策略接口的方法。
3.策略上下文类:负责调用具体策略类的实例,根据用户的需求选择相应的策略进行调用。
示例一:实现不同促销活动
假设有一个电商平台,需要实现多种促销活动来吸引用户购买商品。不同的促销活动有不同的算法,例如:满减、折扣、赠品等。这种情况下,可以使用Python策略模式来实现。
首先,定义一个促销策略接口PromotionStrategy
,定义促销活动的方法do_promotion
:
然后,定义具体的促销策略类,例如:满减、折扣、赠品等。这里以满减和折扣为例:
接下来,定义促销上下文类PromotionContext
,负责调用不同的策略:
最后,可以在客户端代码中动态地选择不同的促销策略:
# 定义促销策略接口
class PromotionStrategy():# 定义促销活动def do_promotion(self, price):pass# 定义具体促销策略
class ReductionPromotion(PromotionStrategy):# 满减def do_promotion(self, price):if price >= 200:return price -50return priceclass DiscountPromotion(PromotionStrategy): # 折扣def do_promotion(self, price):return price * 0.8# 定义上下文类,负责调用不同的促销策略
class PromotionContext():def __init__(self, promotion_strategy:PromotionStrategy):self._promotion_strategy = promotion_strategydef execute_promotion_strategy(self, price):return self._promotion_strategy.do_promotion(price)# 动态选择不同促销策略
promotion_type = "Reduction"
promotion_type = "Discount"if promotion_type == "Reduction":promotion_strategy = ReductionPromotion()
elif promotion_type == "Discount":promotion_strategy = DiscountPromotion()promotion_context = PromotionContext(promotion_strategy)
final_price = promotion_context.execute_promotion_strategy(100)
print(final_price)promotion_type = "Reduction"
# promotion_type = "Discount"if promotion_type == "Reduction":promotion_strategy = ReductionPromotion()
elif promotion_type == "Discount":promotion_strategy = DiscountPromotion()promotion_context = PromotionContext(promotion_strategy)
final_price = promotion_context.execute_promotion_strategy(200)
print(final_price)
运行结果:
80.0
150
上述代码中,客户端代码通过promotion_type
参数来选择不同的促销策略。然后将选择的策略传递给PromotionContext
类,由它来负责调用相应的促销策略。最终获得商品的最终价格final_price
。如果需要增加或删除促销活动,只需增加或删除相应的促销策略类即可,不需要修改客户端代码。
示例二:实现不同搜索算法
假设我们要实现一个搜索引擎,支持多种搜索算法,例如二分查找、线性查找、哈希查找等。为了实现这个功能,我们可以使用策略模式,将不同的搜索算法实现抽象成不同的类,然后在运行时动态地将它们传递到搜索引擎中。具体的实现如下:
# 定义算法类的抽象基类
class SearchAlgorithm():def search(self, array, target):pass# 定义算法:二分法
class BinarySearch(SearchAlgorithm):def search(self, array, target):left, right = 0,len(array) - 1 # 初始化二分法查找的左右边界,此处0, 9。 相当于:left=0, right=len(array)-1while left <= right:mid = (left + right) // 2if array[mid] == target:return mid # 返回查找结果elif array[mid] < target:left = mid + 1else:right = mid -1return -1# 定义算法:线性查找
class LineSearch(SearchAlgorithm):def search(self, array, target):for i in range(len(array)):if array[i] == target:return ireturn -1# 定义搜索引擎
class SearchEngine():def __init__(self, search_algorithm):self.search_algorithm = search_algorithmdef set_search_algorithm(self,search_algorithm):self.search_algorithm = search_algorithmdef search(self,array, target):index = self.search_algorithm.search(array, target) # 调用具体的搜索方法if index != -1:print(f"Found {target} at index {index}")else:print(f"{target} not found in the array.")# 测试代码
array = [1,2,3,4,5,6,7,8,9,10]
target = 5binary_search = BinarySearch()
line_search = LineSearch()search_engine = SearchEngine(binary_search)
search_engine.search(array, target)search_engine = SearchEngine(line_search)
search_engine.search(array, target)
运行结果:
Found 5 at index 4
Found 5 at index 4
在上面的例子中,我们定义了一个SearchAlgorithm
类,它是所有搜索算法类的抽象基类。然后,我们定义了两个具体的搜索算法类BinarySearch
和LinearSearch
,它们分别实现了二分查找和线性查找算法。最后,我们定义了一个SearchEngine
类,它接收一个具体的搜索算法类,并将其存储在search_algorithm
属性中。SearchEngine
类还提供了search
方法,用于执行搜索操作。
在测试代码中,我们首先创建了一个BinarySearch
对象,并用它来创建一个SearchEngine
对象。然后,我们调用search
方法执行搜索操作,结果显示目标值5被找到了。接着,我们将search_algorithm
属性设置为LinearSearch
对象,并再次调用search
方法,这次结果显示目标值5同样被找到了。
通过使用策略模式,我们可以在运行时根据需要切换搜索算法,而不需要修改搜索引擎的实现代码。这样就使得程序更加灵活和易于维护。
left, right = 0, len(array) - 1
这行代码用于初始化二分查找的左右边界。在列表中查找某个元素时,我们通常要在列表中的一段区间内进行查找。一开始,这个区间通常是整个列表。那么,左右边界要怎么确定呢?
对于有序列表,我们很容易想到的是将整个列表均匀地划分成两半,然后查看中间位置的元素与目标元素的大小关系。如果中间位置的元素等于目标元素,就返回对应的索引;如果中间位置的元素小于目标元素,就在右半边继续查找;如果中间位置的元素大于目标元素,就在左半边继续查找。这个过程就是二分查找。
而对于二分查找算法,我们需要用left
和right
两个变量来表示当前查找区间的左右边界。一开始,整个列表就是我们要查找的区间,所以left
的初始值为0,right
的初始值为列表长度减1。这样,在每次查找时,我们就可以根据left
和right
的值来确定当前查找区间的范围。
定义类时带括号和不带括号区别
在Python中,定义类时可以带括号,也可以不带括号。
语法格式为:
class className:# some code here# 或者class className():# some code here
带括号和不带括号的区别在于继承的方式不同。在Python 2.x版本中,带括号和不带括号的定义方式有区别,带括号的类定义方式是旧式类,不带括号的类定义方式是新式类。而在Python 3.x版本中,带括号和不带括号定义方式没有区别。
新式类和旧式类的主要区别在于继承方式不同。在旧式类中,如果没有显式地指定一个特定的父类,那么Python会默认继承由内置类型object
派生出的类;而在新式类中,如果没有显式地指定一个特定的父类,那么Python会默认继承内置类型object
。
因此,如果需要在Python 2.x版本中使用新式类,建议在定义类时使用带括号的方式。在Python 3.x版本中,则可以使用带括号或不带括号的方式定义类,两种方式等效。
默认继承内置类型object
在Python中,如果没有显式地指定一个特定的父类,那么Python会默认继承内置类型object
。下面是一个例子:
class MyClass:passprint(type(MyClass)) # <class 'type'>
print(type(MyClass())) # <class '__main__.MyClass'>
在上面的例子中,我们定义了一个空的类MyClass
,并没有指定父类。我们可以通过调用type()
函数来查看MyClass
的类型以及用MyClass()
创建的实例的类型,都是type
和__main__.MyClass
,这说明Python默认继承了内置类型object
。
如果我们明确指定了一个父类,那么Python就会直接继承这个父类,例如:
class MyBaseClass:passclass MyClass(MyBaseClass):passprint(type(MyClass)) # <class 'type'>
print(type(MyClass())) # <class '__main__.MyClass'>
在上面的例子中,我们定义了一个空的父类MyBaseClass
,并让MyClass
类继承自MyBaseClass
。此时,MyClass
的类型仍然是type
,但是MyClass()
创建的实例的类型变为了__main__.MyClass
,这说明MyClass
类已经从MyBaseClass
类继承了一些属性和方法。
相关文章:

Python策略模式介绍、使用方法
一、Python策略模式介绍 Python策略模式(Strategy Pattern)是一种软件设计模式,用于通过将算法封装为独立的对象,而使得它们可以在运行时动态地相互替换。该模式使得算法的变化独立于使用它们的客户端,从而达到代码的…...

城市气象数据可视化:洞察气候变化,构建智慧城市
随着城市化进程的加速,城市气象数据的采集和分析变得越来越重要。气象数据不仅影响着人们的生活和出行,还与城市的发展和规划息息相关。在数字化时代,如何将城市中各个气象数据进行可视化,让复杂的数据变得简单易懂,成…...

Rust-IO
use std::io::Write; fn main() {/*std::io::stdin() 返回标准输入流stdin的句柄。read_line() stdin的句柄的一个方法,从标准输入流中读取一行数据返回一个Result枚举。会自动删除行尾的换行符\n。unwrap() 是一个帮助的方法,简化恢复错误的处理。返回R…...

cp -r 源目录 目标目录
在Linux中,要复制目录可以使用cp命令。cp命令用于复制文件和目录。要复制整个目录及其内容,可以使用 -r 或 --recursive 参数来递归地复制目录。以下是示例命令:bash cp -r 源目录 目标目录其中: 源目录是要复制的目录的路径。目…...

redis之Bitmap
位图数据结构其实并不是一个全新的玩意,我们可以简单的认为就是个数组,只是里面的内容只能为0或1而已(二进制位数组)。 GETBIT用于返回位数组在偏移量上的二进制位的值。值得我们注意的是,GETBIT的时间复杂度是O(1)。 GETBIT命令的执行过程如…...

建设数据中台到底有啥用?
最近专注在数据和人工智能领域,从数据仓库、商业智能、主数据管理到大数据平台的建设,经过很多项目的沉淀和总结,最后我和团队一起总结了精益数据创新的体系。一直战斗在企业信息化一线。 企业为什么要建设数据中台,数据中台对于…...

[运维|系统] Centos设置本地编码
以下是在CentOS上更改系统编码的一般步骤: 使用locale命令查看当前的系统编码: locale如果需要更改系统编码,可以使用类似下面的命令来生成相应的locale设置(以UTF-8为例): sudo localedef -i en_US -f …...

深入探索Python中的os.listdir函数
深入探索Python中的os.listdir函数 1. 引言 在Python中,文件和目录操作是常见的任务之一。而os.listdir()函数是Python中用于获取指定目录下所有文件和子目录的函数之一。本篇博客将深入探索os.listdir()函数的用法和注意事项。 2. os模块简介 Python的os模块是…...

ROS1ROS2之CmakeList.txt和package.xml用法详解
前言:目前还在学习ROS无人机框架中,,, 更多更新文章详见我的个人博客主页【前往】 文章目录 1. CMakeLists.txt与package.xml的作用2. 生成CMakeLists.txt2.1 ROS12.2 ROS2 3. CMakeLists.txt编写3.1 ROS13.2 ROS2 4. package.xml…...

C#设计模式之---适配器模式
适配器模式(Adapter Pattern) 适配器模式(Adapter Pattern)也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。适配器模式是一种结构型模式,一个适配使得因接口不兼容而不能在一起工作的类工作在一起…...

串口设备驱动
文章目录 一、串口简介二、Linux下串口驱动框架uart_driver 结构体uart_port 的添加与移除三、Linux下串口驱动工作流程四、Linux下串口应用开发终端工作模式多线程例程一、串口简介 串口全称叫做串行接口,通常也叫做 COM 接口,串行接口指的是数据一个一个的顺序传输,通信线…...

Nginx实现反向代理和负载均衡
Nginx安装 本文章主要介绍下,如何使用Nginx来实现反向代理和负载均衡,Nginx安装和基础知识,可参考我的这篇文章 Nginx安装。 Nginx实现反向代理 实现反向代理需要准备两台Nginx服务器。一台Nginx服务器A,ip为 192.168.206.140&…...

小米手机MIUI优化的影响
1. 小/红米手机的MIUI优化选项 2. MIUI优化选项的影响 2.1 MIUI优化会影响应用信息展示 MIUI优化选项会影响到应用信息的内容展示,具体如下图所示: 如果我们需要在应用信息里展示自启动入口,那我们就需要开启MIUI优化。 2.2 MIUI优化会影…...

【图论】kruskal算法
一.介绍 Kruskal(克鲁斯卡尔)算法是一种用于解决最小生成树问题的贪心算法。最小生成树是指在一个连通无向图中,选择一棵包含所有顶点且边权重之和最小的树。 下面是Kruskal算法的基本步骤: 将图中的所有边按照权重从小到大进行…...

Django框架:使用channels实现websocket,配置和项目实际使用
一、基本配置 依赖包: Django3.2 django-cors-headers3.5.0 redis4.6.0 #操作redis数据库的 channels3.0.0 #websocket channels-redis4.1.0 #通道层需要,依赖redis包项目目录结构: study_websocket --study_websocket --__init__.py --s…...

基于RK3588+FPGA+AI算法定制的智慧交通与智能安防解决方案
随着物联网、大数据、人工智能等技术的快速发展,边缘计算已成为当前信息技术领域的一个热门话题。在物联网领域,边缘计算被广泛应用于智慧交通、智能安防、工业等多个领域。因此,基于边缘计算技术的工业主板设计方案也受到越来越多人的关注。…...

AI面试官:LINQ和Lambda表达式(一)
AI面试官:LINQ和Lambda表达式(一) 当面试官面对C#中关于LINQ和Lambda表达式的面试题时,通常会涉及这两个主题的基本概念、用法、实际应用以及与其他相关技术的对比等。以下是一些可能的面试题目,附带简要解答和相关案…...

FPGA学习——FPGA利用状态机实现电子锁模拟
文章目录 一、本次实验简介二、源码及分析三、总结 一、本次实验简介 本次是实验是为了利用状态机模拟电子锁,相关要求如下: 顺序输入4位密码,密码为1234,用按键来键入密码用led灯指示键入第几位密码,(博…...

Bert经典变体学习
ALBert ALBERT就是为了解决模型参数量大以及训练时间过长的问题。ALBERT最小的参数只有十几M, 效果要比BERT低1-2个点,最大的xxlarge也就200多M。可以看到在模型参数量上减少的还是非常明显的,但是在速度上似乎没有那么明显。最大的问题就是这种方式其实…...

uniapp checkbox radio 样式修改
文章目录 通过查看代码,发现 before部分是设置样式的主要属性 我们要设置的话,就要设置checkbox::before的属性。 其中的content表示内容,比如内部的对勾 那么我们设置的时候,比如设置disabletrue的时候或者checkedtrue的时候&…...

电脑重启后VScode快捷方式失效,找不到Code.exe
问题描述 下班回家关了部分程序就直接关机了,回家后重启电脑发现vscode的快捷方式就失效了,提示Code.exe已被移动或删除。 解决方法 查看你的vscode安装目录,Microsoft VS Code目录下大概率会存在一个名为_的文件夹,然后会发现…...

C语言实现扫雷游戏
test.c源文件 - 扫雷游戏测试 game.h头文件 - 扫雷游戏函数的声明 game.c源文件 - 扫雷游戏函数的实现 1.布置雷 -- 存放雷的雷盘 9*9 数组设计成11*11 上下左右方各多一行,保证周围8的范围 雷 - 1 不是雷 - 0 2.排查雷 主题测试源文件代码 &…...

蓝图节点编辑器
打印字符串 第02章 蓝图结构 03 -注释和重新路由_哔哩哔哩_bilibili 第02章 蓝图结构 04 - 变量_哔哩哔哩_bilibili 第03章 蓝图简易门 01 - 箱子碰撞_哔哩哔哩_bilibili 第03章 蓝图简易门 02 - 静态Mesh和箭头_哔哩哔哩_bilibili 第03章 蓝图简易门 03 - 设置相对旋转节点_哔…...

MySql 知识大汇总
数据库索引 数据库索引是一种数据结构,用于提高数据库查询的速度和效率。索引可以看作是表中一列或多列的值的快速查找方式,类似于书籍的目录。通过创建索引,可以减少数据库的扫描量,加快数据的检索速度。 常见的索引类型 常见…...

深入浅出Pytorch函数——torch.sum
分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出Pytorch函数——torch.Tensor 函数torch.sum有两种形式: torch.sum(input, *, dtypeNone):返回输入张量input所有元素的和。torch.sum(input, dim, keepdimFalse, *,…...

Git克隆文件不显示绿色勾、红色感叹号等图标
1、问题 Git和TorToiseGit安装后,Git克隆的文件不会显示绿色勾、红色感叹号等图标。 2、检查注册表 2.1、打开注册表 (1)WinR打开运行窗口,输入regedit,点击确定,打开注册表编辑器。 2.2、找如下路径 (1)找到路径 计算机\HKEY_…...

SOC FPGA之HPS模型设计(一)
目录 一、建立HPS硬件系统模型 1.1 GHRD 1.2 从0开始搭建HPS 1.2.1 FPGA Interfaces 1.2.1.1 General 1.2.1.2 AXI Bridge 1.2.1.3 FPGA-to-HPS SDRAM Interface 1.2.1.4 DMA Peripheral Request 1.2.1.5 Interrupts 1.2.1.6 EMAC ptp interface 1.2.2 Peripheral P…...

解决openstack重启swift服务后报错
swift重启报错 问题描述解决办法 问题描述 swift服务正常状态如下 [rootcontroller ~]# swift statAccount: AUTH_8bde12ff804e42498661b7454994c446Containers: 0Objects: 0Bytes: 0X-Put-Timestamp: 1690507907.67931X-Timestamp: 1690507907.67931X-Trans-Id: tx56d22fa13…...

[Linux]进程控制详解!!(创建、终止、等待、替换)
hello,大家好,这里是bang___bang_,在上两篇中我们讲解了进程的概念、状态和进程地址空间,本篇讲解进程的控制!!包含内容有进程创建、进程等待、进程替换、进程终止!! 附上前2篇文章…...

全面适配 | 走近openGauss数据库+鲲鹏欧拉操作系统
引入 全面适配 | openEuler操作系统 openGauss数据库 开篇 1、openEuler欧拉操作系统 百度百科:openEuler是覆盖全场景的创新平台,在引领内核创新,夯实云化基座的基础上,面向计算架构互联总线、存储介质发展新趋势,…...