Python设计模式详解:策略模式(Strategy Pattern)实战指南

Python设计模式详解:策略模式实战指南

    • 什么是策略模式?
      • 核心组件
    • 基础实现
    • 利用Python特性的高级实现
    • 使用装饰器的策略模式
    • 策略模式的优势
    • 策略模式的适用场景
    • 实际应用案例:电商折扣系统
    • 注意事项
    • 总结

在面向对象编程中,设计模式为常见问题提供了可重用的解决方案。策略模式是行为设计模式中最广泛使用的一种,它允许在运行时选择算法。本文将全面介绍如何在Python中理解和实现策略模式。

什么是策略模式?

策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换。它允许算法独立于使用它们的客户端而变化。

核心组件

  • 上下文(Context):维护一个指向策略对象的引用
  • 策略(Strategy):所有支持算法的公共接口
  • 具体策略(Concrete Strategies):策略接口的具体实现

基础实现

让我们从一个简单的支付系统示例开始:

from abc import ABC, abstractmethod# 策略接口
class PaymentStrategy(ABC):@abstractmethoddef pay(self, amount):pass# 具体策略实现
class CreditCardPayment(PaymentStrategy):def __init__(self, name, card_number, cvv):self.name = nameself.card_number = card_numberself.cvv = cvvdef pay(self, amount):print(f"使用信用卡支付 ${amount},卡号尾号 {self.card_number[-4:]}")class PayPalPayment(PaymentStrategy):def __init__(self, email):self.email = emaildef pay(self, amount):print(f"使用PayPal支付 ${amount},账户 {self.email}")class BitcoinPayment(PaymentStrategy):def __init__(self, wallet_address):self.wallet_address = wallet_addressdef pay(self, amount):print(f"使用比特币支付 ${amount},钱包地址 {self.wallet_address[:8]}...")# 上下文
class ShoppingCart:def __init__(self):self.items = []self.payment_strategy = Nonedef add_item(self, item, price):self.items.append((item, price))def set_payment_strategy(self, strategy):self.payment_strategy = strategydef calculate_total(self):return sum(price for item, price in self.items)def checkout(self):if not self.payment_strategy:raise Exception("未设置支付策略")total = self.calculate_total()self.payment_strategy.pay(total)# 使用示例
cart = ShoppingCart()
cart.add_item("笔记本电脑", 1200)
cart.add_item("鼠标", 25)# 使用信用卡支付
cart.set_payment_strategy(CreditCardPayment("张三", "1234567890123456", "123"))
cart.checkout()# 使用PayPal支付
cart.set_payment_strategy(PayPalPayment("zhangsan@example.com"))
cart.checkout()

利用Python特性的高级实现

Python的动态特性允许更灵活的实现:

from enum import Enum
from typing import Callable# 使用函数作为策略
def bubble_sort(data):print("使用冒泡排序")# 实现细节return sorted(data)def quick_sort(data):print("使用快速排序")# 实现细节return sorted(data)def merge_sort(data):print("使用归并排序")# 实现细节return sorted(data)# 策略枚举
class SortStrategy(Enum):BUBBLE = bubble_sortQUICK = quick_sortMERGE = merge_sortclass Sorter:def __init__(self, strategy: SortStrategy):self.strategy = strategydef sort(self, data):return self.strategy.value(data)# 使用示例
data = [64, 34, 25, 12, 22, 11, 90]
sorter = Sorter(SortStrategy.QUICK)
result = sorter.sort(data)

使用装饰器的策略模式

# 策略注册装饰器
strategies = {}def register_strategy(name):def decorator(func):strategies[name] = funcreturn funcreturn decorator@register_strategy("discount_10")
def ten_percent_discount(price):return price * 0.9@register_strategy("discount_20")
def twenty_percent_discount(price):return price * 0.8@register_strategy("holiday_special")
def holiday_discount(price):return price * 0.7 if price > 100 else priceclass PriceCalculator:def __init__(self, strategy_name):self.strategy = strategies.get(strategy_name)if not self.strategy:raise ValueError(f"未知的策略: {strategy_name}")def calculate(self, price):return self.strategy(price)# 使用示例
calculator = PriceCalculator("holiday_special")
final_price = calculator.calculate(150)
print(f"最终价格: ${final_price}")

策略模式的优势

  1. 算法可以自由切换:可以在运行时动态更换算法
  2. 避免使用多重条件判断:替代大量的if-else或switch语句
  3. 扩展性良好:可以方便地添加新的算法
  4. 符合开闭原则:对扩展开放,对修改关闭

策略模式的适用场景

  1. 多个类只有算法不同:当系统中存在大量相似的类,只有行为不同时
  2. 需要算法动态切换:需要在运行时选择不同的算法
  3. 消除复杂的条件分支:替代复杂的if-else或switch语句
  4. 算法需要独立变化:算法的变化不应影响客户端

实际应用案例:电商折扣系统

from abc import ABC, abstractmethod
from datetime import datetimeclass DiscountStrategy(ABC):@abstractmethoddef calculate_discount(self, original_price, quantity):passclass NoDiscount(DiscountStrategy):def calculate_discount(self, original_price, quantity):return original_price * quantityclass BulkDiscount(DiscountStrategy):def calculate_discount(self, original_price, quantity):if quantity >= 10:return original_price * quantity * 0.9  # 10%折扣return original_price * quantityclass SeasonalDiscount(DiscountStrategy):def calculate_discount(self, original_price, quantity):# 假设夏季有折扣current_month = datetime.now().monthif 6 <= current_month <= 8:return original_price * quantity * 0.85  # 15%折扣return original_price * quantityclass MemberDiscount(DiscountStrategy):def __init__(self, is_vip=False):self.is_vip = is_vipdef calculate_discount(self, original_price, quantity):if self.is_vip:return original_price * quantity * 0.8  # 20%折扣return original_price * quantity * 0.95    # 5%折扣class Order:def __init__(self, product_name, price, quantity):self.product_name = product_nameself.price = priceself.quantity = quantityself.discount_strategy = NoDiscount()def set_discount_strategy(self, strategy):self.discount_strategy = strategydef get_total(self):return self.discount_strategy.calculate_discount(self.price, self.quantity)# 使用示例
order = Order("商品A", 100, 15)
print(f"原价: ${order.get_total()}")  # 1500# 设置批量折扣
order.set_discount_strategy(BulkDiscount())
print(f"批量折扣后: ${order.get_total()}")  # 1350# 设置会员折扣
order.set_discount_strategy(MemberDiscount(is_vip=True))
print(f"会员折扣后: ${order.get_total()}")  # 1200

注意事项

  1. 策略数量:如果策略很少且不经常变化,可能不需要使用策略模式
  2. 客户端了解策略:客户端必须了解不同策略的区别才能选择合适的策略
  3. 对象数量增加:每种策略都需要创建一个策略类,可能会增加系统中的对象数量

总结

策略模式是一种非常实用的设计模式,特别适合处理算法需要动态切换的场景。通过将算法封装在独立的类中,可以实现算法的灵活替换,同时保持代码的清晰和可维护性。在Python中,我们可以利用其动态特性,使用函数、装饰器等方式来简化策略模式的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93689.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一次 web 请求响应中,通常那个部分最耗时?

文章目录一次Web请求的完整旅程1. DNS解析2. TCP连接建立3. 发送HTTP请求4. 服务器处理5. 服务器响应6. 浏览器渲染哪个环节通常最耗时&#xff1f;1. 数据库查询2. 外部API调用3. 复杂的业务逻辑如何优化各个环节&#xff1f;1. 数据库优化2. 缓存策略3. 异步处理总结一次Web请…

IO流-概述和体系

1.什么是I0流?存储和读取数据的解决方案|: input 0: output流:像水流一样传输数据2.10流的作用?用于读写数据(本地文件&#xff0c;网络)3. I0流按照流向可以分类哪两种流?输出流:程序-->文件输入流:文件-->程序4. I0流按照操作文件的类型可以分类哪两种流?…

提高建筑舒适度与能源效率,楼宇自控系统意义重大

随着城市化进程的加速和人们对建筑环境要求的不断提高&#xff0c;如何在保证建筑舒适度的同时提升能源效率&#xff0c;成为建筑行业面临的重要课题。楼宇自控系统&#xff08;Building Automation System&#xff0c;简称BAS&#xff09;作为现代智能建筑的核心组成部分&…

学习笔记《区块链技术与应用》第4天 比特币脚本语言

输入0.7 输出0.5 23个确认 不太可能回滚了交易id hash值 版本 locktime 交易剩下时间&#xff1a;0立即生效 confirmation:确认信息 time&#xff1a;产生时间 blocktime&#xff1a;块产生时间vout: 交易中第0个输入 scriptSig&#xff1a;输入脚本&#xff08;input script)n…

3.Linux 系统文件类型与文件权限

1.文件类型Linux 下所有的东西都可以看做文件&#xff0c;Linux 将文件分为以下几种类型&#xff1a;普通文件 ‘-’目录文件 ‘d’管道文件 ‘p’链接文件 ‘l’设备文件&#xff08;块设备 ’b’ 、字符设备 ‘c’&#xff09;套接字文件 ‘s’Linux 上不以文件的扩展名区别文…

订单识别技术原理及场景应用

订单OCR&#xff08;光学字符识别&#xff09;技术通过图像处理和深度学习算法&#xff0c;将纸质或电子版订单中的文字信息转化为结构化数据。以下是其技术原理和典型应用场景的详细解析&#xff1a;一、技术原理剖析1. 核心处理流程图像预处理去噪&#xff1a;消除阴影、折痕…

[优选算法]复写零

题目链接 LeetCode复写零 题目描述 题目解析 一、问题理解 题目要求&#xff1a;给定一个整数数组 arr&#xff0c;在不创建新数组的情况下&#xff0c;将每个出现的 0 复写一遍&#xff08;即一个 0 变成两个 0&#xff09;&#xff0c;同时保持其他元素的相对顺序不变。复…

element UI的el-table组件,实现可以拖动

表格 <div class"main_table"><el-table id"elTableid" :data"fieldArr" border style"width: 100%" row-class-name"drag-row"current-row-key highlight-current-row><el-table-column type"index&qu…

Android Emoji 全面解析:从使用到自定义

引言 Emoji已经成为现代数字通信不可或缺的一部分&#xff0c;这些小小的图标能够跨越语言障碍&#xff0c;直观地表达情感和想法。在Android开发中&#xff0c;正确处理和显示Emoji是提升用户体验的重要环节。本文将全面介绍Android平台上的Emoji支持&#xff0c;包括系统集成…

数据中心入门学习(五):服务器CPU

目录CPU1 概述1.1 概念1.2 冯诺依曼架构1.3 常见参数&#xff08;评估性能&#xff09;1.4 按指令集分类2 CPU发展2.1 发展史2.2 行业产业链2.3 英特尔 Xeon 至强处理器2.4 AMD Zen架构补充1 寄存器、存储器、内存、缓存、硬盘区别与联系&#xff1f;2 浮点单元参考本篇记录和梳…

基于MySQL实现基础图数据库

基于MySQL实现基础图数据库 一、概念 图数据库是一种用于存储和查询具有复杂关系的数据的数据库。在这种数据库中&#xff0c;数据被表示为节点&#xff08;实体&#xff09;和边&#xff08;关系&#xff09;。图数据库的核心优势在于能够快速地查询和处理节点之间的关系。 图…

RAG面试内容整理-9. 查询改写与增强(Query Rewriting, Query Expansion)

查询改写和查询增强是两种提升检索效果的技术,目标是在不改变用户意图的前提下,使检索器收到的查询更全面或明确,从而找到更多相关信息。 查询改写通常指将原始查询转换成语义等价但更明晰的形式。上一节谈到的对话查询改写是一个典型场景。在一般情况下,查询改写也适用于澄…

golang设置http代理

问题场景&#xff1a; golang通过eino的官方agent示例调用duckduckgo进行联网搜索时出现网络问题&#xff0c;电脑此时是挂了工具的浏览器整出打开 官方示例&#xff1a;https://www.cloudwego.io/zh/docs/eino/quick_start/agent_llm_with_tools/ 问题原因&#xff1a;go代码没…

Elasticsearch 现在默认启用 BBQ,并通过 ACORN 实现过滤向量搜索

作者&#xff1a;来自 Elastic Gilad Gal 探索 Elasticsearch 的向量搜索如何以更快的速度、更低的成本提供更优结果。 试用向量搜索&#xff1a;使用这套自定进度的 Search AI 实操学习课程&#xff0c;亲自体验向量搜索。你可以开始免费云试用&#xff0c;或立即在本地机器上…

Java 14 新特性解析与代码示例

Java 14 新特性解析与代码示例 文章目录Java 14 新特性解析与代码示例1. 开关表达式&#xff08;Switch Expressions&#xff09;2. 记录类型&#xff08;Records&#xff09;3. 文本块&#xff08;Text Blocks&#xff09;4. instanceof的模式匹配&#xff08;Pattern Matchin…

在虚拟机ubuntu上修改framebuffer桌面不能显示图像

目录 一、测试程序 二、排查原因 三、为什么 Xorg 会导致程序无法工作&#xff1f; 一、测试程序 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #in…

语言模型的评估指标整理

语言模型&#xff08;Language Models&#xff09;是自然语言处理&#xff08;NLP&#xff09;的核心组件&#xff0c;广泛应用于机器翻译、文本生成、对话系统等领域。随着模型复杂度的提升&#xff0c;如何科学、系统地评估模型性能变得至关重要。评估指标不仅帮助我们理解模…

【开发技术】.Net中配置Serilog日志分级记录

目录 一、目的 二、解决方案 2.1 下载serilog包 2.2 Serilog配置 2.2.1 使用多个File sink配置不同的最小日志级别 2.2.2 使用Filter条件分流到不同文件 三、使用建议 四、文章总结 一、目的 在日常开发中&#xff0c;需要根据不同的场景去记录日志&#xff0c;根据实际…

聊聊如何判断发现的缺陷属于前后端

目录 一、观察缺陷现象 二、检查网络请求&#xff08;核心方法&#xff09; 三、模拟请求验证后端 四、查看日志 五、数据流分析 六、判断前后端缺陷方法 判断发现的缺陷是前后端&#xff0c;可以通过观察缺陷现象&#xff0c;检查网络请求&#xff0c;查看后端日志&…

Python3与MySQL的PyMySQL连接与应用

Python3与MySQL的PyMySQL连接与应用 引言 随着互联网技术的飞速发展,数据库在各个领域的应用日益广泛。MySQL作为一种开源的关系型数据库管理系统,因其稳定性和高效性,被广泛应用于各种场景。Python作为一种高级编程语言,以其简洁、易读、易学等特点,受到了广大开发者的…