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}")
策略模式的優勢
- 算法可以自由切換:可以在運行時動態更換算法
- 避免使用多重條件判斷:替代大量的if-else或switch語句
- 擴展性良好:可以方便地添加新的算法
- 符合開閉原則:對擴展開放,對修改關閉
策略模式的適用場景
- 多個類只有算法不同:當系統中存在大量相似的類,只有行為不同時
- 需要算法動態切換:需要在運行時選擇不同的算法
- 消除復雜的條件分支:替代復雜的if-else或switch語句
- 算法需要獨立變化:算法的變化不應影響客戶端
實際應用案例:電商折扣系統
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
注意事項
- 策略數量:如果策略很少且不經常變化,可能不需要使用策略模式
- 客戶端了解策略:客戶端必須了解不同策略的區別才能選擇合適的策略
- 對象數量增加:每種策略都需要創建一個策略類,可能會增加系統中的對象數量
總結
策略模式是一種非常實用的設計模式,特別適合處理算法需要動態切換的場景。通過將算法封裝在獨立的類中,可以實現算法的靈活替換,同時保持代碼的清晰和可維護性。在Python中,我們可以利用其動態特性,使用函數、裝飾器等方式來簡化策略模式的實現。