Python设计模式详解:策略模式实战指南
在面向对象编程中,设计模式为常见问题提供了可重用的解决方案。策略模式是行为设计模式中最广泛使用的一种,它允许在运行时选择算法。本文将全面介绍如何在Python中理解和实现策略模式。
什么是策略模式?
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换。它允许算法独立于使用它们的客户端而变化。
核心组件
- 上下文(Context):维护一个指向策略对象的引用
- 策略(Strategy):所有支持算法的公共接口
- 具体策略(Concrete Strategies):策略接口的具体实现
基础实现
让我们从一个简单的支付系统示例开始:
from abc import ABC, abstractmethod
# 策略接口
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
# 具体策略实现
class CreditCardPayment(PaymentStrategy):
def __init__(self, name, card_number, cvv):
self.name = name
self.card_number = card_number
self.cvv = cvv
def pay(self, amount):
print(f"使用信用卡支付 ${amount},卡号尾号 {self.card_number[-4:]}")
class PayPalPayment(PaymentStrategy):
def __init__(self, email):
self.email = email
def pay(self, amount):
print(f"使用PayPal支付 ${amount},账户 {self.email}")
class BitcoinPayment(PaymentStrategy):
def __init__(self, wallet_address):
self.wallet_address = wallet_address
def pay(self, amount):
print(f"使用比特币支付 ${amount},钱包地址 {self.wallet_address[:8]}...")
# 上下文
class ShoppingCart:
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item, price):
self.items.append((item, price))
def set_payment_strategy(self, strategy):
self.payment_strategy = strategy
def 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_sort
QUICK = quick_sort
MERGE = merge_sort
class Sorter:
def __init__(self, strategy: SortStrategy):
self.strategy = strategy
def 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] = func
return func
return 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 price
class 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}")
策略模式的优势
- 算法可以自由切换:可以在运行时动态更换算法
- 避免使用多重条件判断:替代大量的if-else或switch语句
- 扩展性良好:可以方便地添加新的算法
- 符合开闭原则:对扩展开放,对修改关闭
策略模式的适用场景
- 多个类只有算法不同:当系统中存在大量相似的类,只有行为不同时
- 需要算法动态切换:需要在运行时选择不同的算法
- 消除复杂的条件分支:替代复杂的if-else或switch语句
- 算法需要独立变化:算法的变化不应影响客户端
实际应用案例:电商折扣系统
from abc import ABC, abstractmethod
from datetime import datetime
class DiscountStrategy(ABC):
@abstractmethod
def calculate_discount(self, original_price, quantity):
pass
class NoDiscount(DiscountStrategy):
def calculate_discount(self, original_price, quantity):
return original_price * quantity
class BulkDiscount(DiscountStrategy):
def calculate_discount(self, original_price, quantity):
if quantity >= 10:
return original_price * quantity * 0.9 # 10%折扣
return original_price * quantity
class SeasonalDiscount(DiscountStrategy):
def calculate_discount(self, original_price, quantity):
# 假设夏季有折扣
current_month = datetime.now().month
if 6 <= current_month <= 8:
return original_price * quantity * 0.85 # 15%折扣
return original_price * quantity
class MemberDiscount(DiscountStrategy):
def __init__(self, is_vip=False):
self.is_vip = is_vip
def 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_name
self.price = price
self.quantity = quantity
self.discount_strategy = NoDiscount()
def set_discount_strategy(self, strategy):
self.discount_strategy = strategy
def 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
注意事项
- 策略数量:如果策略很少且不经常变化,可能不需要使用策略模式
- 客户端了解策略:客户端必须了解不同策略的区别才能选择合适的策略
- 对象数量增加:每种策略都需要创建一个策略类,可能会增加系统中的对象数量
总结
策略模式是一种非常实用的设计模式,特别适合处理算法需要动态切换的场景。通过将算法封装在独立的类中,可以实现算法的灵活替换,同时保持代码的清晰和可维护性。在Python中,我们可以利用其动态特性,使用函数、装饰器等方式来简化策略模式的实现。