目录
策略模式(Strategy Pattern)是一种行为型设计模式,旨在通过定义一系列的算法(或策略),将每个算法封装起来,使它们可以互换,并使得算法的变化独立于使用算法的客户端。
主要组成
-
Context(上下文):上下文类通常持有一个策略对象的引用,并且委托给策略来执行某些具体操作。上下文类通常不直接包含具体的算法,而是与策略接口交互。
-
Strategy(策略接口):策略接口定义了所有支持的算法的通用接口。不同的策略类实现这个接口,提供不同的具体算法。
-
ConcreteStrategy(具体策略类):每个具体策略类实现了策略接口,并定义了具体的算法或行为。
优点
-
开放封闭原则:策略模式使得新的算法可以不修改原有代码的情况下新增,符合开放封闭原则(对扩展开放,对修改封闭)。
-
避免多重条件语句:策略模式避免了使用大量的
if-else
或switch-case
语句来选择不同的算法。 -
增强算法的独立性:将算法独立出来,使得算法可以在不同的上下文中复用。
缺点
-
客户端必须知道所有的策略并且自行决定使用哪一个策略。
-
如果策略非常多,那么对于策略的选择可能会变得复杂。
使用场景:
-
需要动态改变算法或行为时:例如,根据用户的选择动态切换不同的算法或策略。
-
多种算法可以互相替代时:例如,多个支付方式(如信用卡支付、支付宝支付、微信支付等)可以通过策略模式进行切换。
-
避免使用复杂的条件语句时:例如,如果有多个条件判断可以决定程序的行为,可以通过策略模式使得代码更加简洁和易于维护。
示例代码
需求:为不同的金额范围(如 100 元、200 元、500 元 等)实现具体的折扣策略。
普通写法:
def get_discount_amount(amount: float) -> float:
if amount >= 1000:
return amount * 0.85
elif amount >= 500:
return amount * 0.90
elif amount >= 200:
return amount * 0.92
elif amount >= 100:
return amount * 0.95
else:
return amount
if __name__ == "__main__":
amounts = [90, 150, 250, 600, 1200]
for amount in amounts:
discounted_amount = get_discount_amount(amount)
print(f"原价 {amount} 元,折后价 {discounted_amount} 元")
策略模式:
from abc import ABC, abstractmethod
# 策略接口
class DiscountStrategy(ABC):
@abstractmethod
def calculate_discount(self, amount: float) -> float:
pass
# 具体策略:无折扣
class NoDiscountStrategy(DiscountStrategy):
def calculate_discount(self, amount: float) -> float:
return amount
# 具体策略类:100元打95折
class DiscountStrategy100(DiscountStrategy):
def calculate_discount(self, amount: float) -> float:
return amount * 0.95
# 具体策略类:200元打92折
class DiscountStrategy200(DiscountStrategy):
def calculate_discount(self, amount: float) -> float:
return amount * 0.92
# 具体策略类:500元打9折
class DiscountStrategy500(DiscountStrategy):
def calculate_discount(self, amount: float) -> float:
return amount * 0.90
# 具体策略类:1000元以上打8.5折
class DiscountStrategy1000(DiscountStrategy):
def calculate_discount(self, amount: float) -> float:
return amount * 0.85
# 上下文类
class DiscountContext:
def __init__(self, strategy: DiscountStrategy):
# 持有一个策略对象的引用
self._strategy = strategy
def execute_discount(self, amount: float) -> float:
return self._strategy.calculate_discount(amount)
# 客户端代码:根据金额选择策略
def get_discount_strategy(amount: float) -> DiscountStrategy:
# 客户端必须知道所有的策略并且自行决定使用哪一个策略。
if amount >= 1000:
return DiscountStrategy1000()
elif amount >= 500:
return DiscountStrategy500()
elif amount >= 200:
return DiscountStrategy200()
elif amount >= 100:
return DiscountStrategy100()
else:
return NoDiscountStrategy()
# 客户端代码
if __name__ == "__main__":
# 如明确知道所需策略
amount = 250
context = DiscountContext(DiscountStrategy200())
discounted_amount = context.execute_discount(250)
print(f"原价 {amount} 元,折后价 {discounted_amount} 元")
print('-' * 20)
# 需要动态选取策略
amounts = [90, 150, 250, 600, 1200]
for amount in amounts:
# 获取合适的折扣策略
strategy = get_discount_strategy(amount)
# 创建上下文,执行折扣计算
context = DiscountContext(strategy)
discounted_amount = context.execute_discount(amount)
print(f"原价 {amount} 元,折后价 {discounted_amount} 元")
策略模式与 if-else
的关系:
在策略模式中,我们的目标是将不同的策略(在这里是折扣策略)封装到不同的策略类中,然后通过上下文类(DiscountContext
)来选择合适的策略执行。策略模式本身并不要求在选择策略时完全消除所有的 if-else
,但其核心思想是将这些条件判断封装在策略类中,而不是集中在外部逻辑中。
区别总结
方面 | 策略模式 | 直接使用 if-else |
---|---|---|
添加新规则 | 只需添加新的策略类,客户端代码稍作调整。 | 需要修改函数。 |
开闭原则 | 符合开闭原则,对扩展开放,对修改关闭。 | 违反开闭原则,每次修改都需要改动函数。 |
职责分离 | 折扣逻辑封装在独立的策略类中,职责清晰。 | 折扣逻辑和业务逻辑耦合在一起。 |
动态切换策略 | 支持运行时动态切换策略,灵活性高。 | 静态逻辑,无法动态调整。 |
代码复杂度 | 适合复杂场景,代码结构清晰。 | 适合简单场景,规则增多后难以维护。 |