Strategy(策略)设计模式 是一种行为型设计模式,旨在定义一组算法或行为,并使它们可以相互替换,且独立于使用这些算法的客户端代码。它让代码更加灵活,便于扩展和维护。
1. 定义
Strategy 模式将算法的定义与使用分离,使得可以在运行时更改某些行为或算法而不影响客户端代码。这种模式鼓励用组合而非继承来实现动态行为。
2. 适用场景
- 需要在运行时动态切换算法或行为时。
- 如支付方式选择(信用卡、PayPal 等)。
- 多个类只在算法或行为上有所不同时。
- 避免将不同的算法硬编码在一个类中。
- 希望避免使用大量
if-elif
或switch-case
语句时。
3. 结构
-
Strategy(策略接口)
定义所有支持的算法或行为的公共接口。 -
ConcreteStrategy(具体策略)
实现具体的算法或行为。 -
Context(上下文)
保存对 Strategy 对象的引用,供客户端调用和动态更换。
4. Python 实现
以下是实现 Strategy 模式的代码示例:
示例:支付系统的策略模式实现
from abc import ABC, abstractmethod
# Strategy 接口
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
# 具体策略:信用卡支付
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number, card_holder):
self.card_number = card_number
self.card_holder = card_holder
def pay(self, amount):
print(f"Paid {amount} using Credit Card ({self.card_holder}).")
# 具体策略:PayPal 支付
class PayPalPayment(PaymentStrategy):
def __init__(self, email):
self.email = email
def pay(self, amount):
print(f"Paid {amount} using PayPal ({self.email}).")
# 具体策略:现金支付
class CashPayment(PaymentStrategy):
def pay(self, amount):
print(f"Paid {amount} using Cash.")
# Context
class PaymentContext:
def __init__(self, strategy: PaymentStrategy):
self.strategy = strategy
def set_strategy(self, strategy: PaymentStrategy):
self.strategy = strategy
def execute_payment(self, amount):
self.strategy.pay(amount)
# 客户端
if __name__ == "__main__":
# 使用 PayPal 支付
paypal_payment = PayPalPayment(email="user@example.com")
context = PaymentContext(strategy=paypal_payment)
context.execute_payment(100)
# 切换到信用卡支付
credit_card_payment = CreditCardPayment(card_number="1234-5678-9876-5432", card_holder="John Doe")
context.set_strategy(strategy=credit_card_payment)
context.execute_payment(200)
# 切换到现金支付
cash_payment = CashPayment()
context.set_strategy(strategy=cash_payment)
context.execute_payment(50)
5. 优点和缺点
优点:
- 开闭原则:添加新策略时,不需要修改上下文和客户端代码。
- 消除条件语句:避免使用大量的
if-elif
或switch-case
语句。 - 灵活性:可以在运行时更换算法。
- 可维护性:每种算法有独立的类,便于管理。
缺点:
- 增加类的数量:每种策略都需要一个独立的类。
- 可能导致复杂性:对于简单的问题,引入 Strategy 模式可能显得多余。
- 上下文依赖策略的实现:上下文需要知道策略的接口。
6. 扩展用法
6.1 数据处理场景
假设你有不同的排序算法,并希望根据数据特点选择最优算法。
class SortStrategy(ABC):
@abstractmethod
def sort(self, data):
pass
class QuickSort(SortStrategy):
def sort(self, data):
print("Using QuickSort")
return sorted(data)
class MergeSort(SortStrategy):
def sort(self, data):
print("Using MergeSort")
return sorted(data) # 实际可以实现自己的归并排序
class Context:
def __init__(self, strategy: SortStrategy):
self.strategy = strategy
def set_strategy(self, strategy: SortStrategy):
self.strategy = strategy
def execute_sort(self, data):
return self.strategy.sort(data)
if __name__ == "__main__":
data = [3, 1, 4, 1, 5]
context = Context(strategy=QuickSort())
print(context.execute_sort(data))
context.set_strategy(MergeSort())
print(context.execute_sort(data))
6.2 结合 Python 动态特性
Python 的动态特性可以减少显式类的数量,例如通过函数来实现策略模式。
# 策略定义为函数
def quick_sort(data):
print("Using QuickSort")
return sorted(data)
def merge_sort(data):
print("Using MergeSort")
return sorted(data)
class Context:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def execute_sort(self, data):
return self.strategy(data)
if __name__ == "__main__":
data = [3, 1, 4, 1, 5]
context = Context(strategy=quick_sort)
print(context.execute_sort(data))
context.set_strategy(merge_sort)
print(context.execute_sort(data))
7. 设计原则
- 遵循 开闭原则,可以轻松添加新策略而不修改现有代码。
- 使用 组合优于继承 的原则,动态地组合行为。
8. 总结
Strategy 模式在需要动态改变算法、消除复杂条件分支或提高代码可扩展性时非常有用。Python 的动态特性(如函数作为对象)也为实现 Strategy 模式提供了简洁的方式,适合根据具体需求选择实现形式。