目录

  1. 策略模式简介
  2. 策略模式的结构
  3. 策略模式的优缺点
  4. 策略模式的实现
    • 4.1 Python 示例
  5. 策略模式的应用场景
  6. 出站链接
  7. 站内链接
  8. 参考资料

1. 策略模式简介

策略模式(Strategy Pattern) 是一种行为型设计模式,它定义了一系列算法或策略,并让这些算法或策略可以相互替换,策略模式让算法的变化独立于使用算法的客户。通过引入策略模式,可以将不同的行为或算法封装在不同的策略类中,使得客户端可以根据需要选择使用哪种策略,而无需修改代码。

为什么使用策略模式?

  • 避免条件语句:在多个算法/策略选择时,传统做法往往使用大量 if-elseswitch 语句,而策略模式将这些算法封装在独立的策略类中,避免了复杂的条件判断。
  • 增强可扩展性:策略模式让你可以通过扩展新策略来增加新的行为,而不需要修改已有的代码,符合开闭原则(Open/Closed Principle)。
  • 提高代码复用:将具体的算法封装成策略对象,可以提高算法的复用性,减少重复代码。

2. 策略模式的结构

策略模式通常涉及以下几个角色:

角色作用
Context(上下文)持有一个策略对象的引用,并通过该策略对象来执行具体的算法。
Strategy(策略接口)声明一个公共接口,所有具体的策略类都需要实现该接口。
ConcreteStrategy(具体策略类)实现策略接口,封装具体的算法或行为。不同的策略类实现不同的算法。

UML 类图

┌──────────────────┐
│   Context        │  (上下文)
│  + set_strategy()│
│  + execute()     │
└─────────▲────────┘
          │
┌──────────────────┐
│   Strategy       │  (策略接口)
│  + execute()     │
└─────────▲────────┘
          │
┌──────────────────┐
│ ConcreteStrategyA│  (具体策略A)
│  + execute()     │
└─────────▲────────┘
          │
┌──────────────────┐
│ ConcreteStrategyB│  (具体策略B)
│  + execute()     │
└──────────────────┘


3. 策略模式的优缺点

优点

  1. 避免使用条件语句:将不同的算法/行为封装成独立的策略类,可以避免使用 if-elseswitch 语句,使代码更加简洁。
  2. 易于扩展:如果需要添加新的算法或策略,只需添加新的策略类,不需要修改现有的代码,符合开闭原则。
  3. 提高代码复用性:策略模式将具体算法封装在策略类中,允许它们在不同的上下文中重复使用。
  4. 减少类的复杂性:通过将不同的算法或行为分离到不同的策略类中,使得每个策略类的责任单一,减少了类的复杂性。

缺点

  1. 增加类的数量:每一个具体的策略都会引入一个新的类,这可能导致类的数量增加,增加系统的复杂度。
  2. 客户端必须了解所有策略:在某些情况下,客户端需要了解所有策略,并选择合适的策略,这可能使客户端的代码变得复杂。
  3. 策略切换过于频繁:如果策略切换过于频繁,可能会导致上下文对象和策略对象之间的切换管理复杂。

4. 策略模式的实现

4.1 Python 示例

场景:模拟一个折扣系统,不同的顾客有不同的折扣策略,客户可以选择合适的折扣策略来计算折扣。

# 1. 策略接口:定义折扣策略的统一接口
class DiscountStrategy:
    def apply_discount(self, price):
        pass

# 2. 具体策略A:普通顾客,提供10%折扣
class RegularDiscount(DiscountStrategy):
    def apply_discount(self, price):
        return price * 0.9

# 3. 具体策略B:VIP顾客,提供20%折扣
class VIPDiscount(DiscountStrategy):
    def apply_discount(self, price):
        return price * 0.8

# 4. 具体策略C:新顾客,提供5%折扣
class NewCustomerDiscount(DiscountStrategy):
    def apply_discount(self, price):
        return price * 0.95

# 5. 上下文类:客户,持有一个具体策略
class Customer:
    def __init__(self, strategy: DiscountStrategy):
        self._strategy = strategy

    def set_strategy(self, strategy: DiscountStrategy):
        self._strategy = strategy

    def get_discounted_price(self, price):
        return self._strategy.apply_discount(price)

# 6. 客户端代码
if __name__ == "__main__":
    price = 100  # 原价

    # 创建一个普通顾客并计算折扣
    regular_customer = Customer(RegularDiscount())
    print(f"Regular customer price: ${regular_customer.get_discounted_price(price)}")

    # 创建一个VIP顾客并计算折扣
    vip_customer = Customer(VIPDiscount())
    print(f"VIP customer price: ${vip_customer.get_discounted_price(price)}")

    # 创建一个新顾客并计算折扣
    new_customer = Customer(NewCustomerDiscount())
    print(f"New customer price: ${new_customer.get_discounted_price(price)}")

输出结果:

Regular customer price: $90.0
VIP customer price: $80.0
New customer price: $95.0

在这个例子中,DiscountStrategy 是策略接口,定义了折扣方法 apply_discount,然后具体的策略类如 RegularDiscountVIPDiscountNewCustomerDiscount 实现了该接口。Customer 类作为上下文类,持有一个策略对象,并通过 get_discounted_price 方法来执行策略。不同的策略对象可以在运行时通过 set_strategy 方法动态切换。


5. 策略模式的应用场景

适用于以下情况

  1. 多个算法/行为的选择
    • 当需要在多个算法中选择时,策略模式非常有效。它允许客户端动态地选择策略,从而避免在代码中使用大量条件判断语句。
  2. 电商系统中的促销策略
    • 电商平台可能根据不同的促销策略(如满减、打折、优惠券等)来计算价格。使用策略模式可以将不同的促销策略封装为独立的策略类,方便扩展和维护。
  3. 支付系统中的支付方式选择
    • 支付系统可能支持多种支付方式(如支付宝、微信支付、信用卡支付等),策略模式可以将每种支付方式封装为独立的策略类,根据用户选择的支付方式执行相应的支付逻辑。
  4. 图形编辑器中的绘制策略
    • 在图形编辑器中,绘制图形的算法可能有多种(如绘制矩形、圆形、多边形等),策略模式可以将这些绘制算法封装为不同的策略类,用户可以选择不同的绘制策略。

真实案例

  • 排序算法的选择
    • 当需要对数据进行排序时,可以根据不同的情况选择不同的排序算法,如快速排序、归并排序、冒泡排序等。策略模式可以封装这些排序算法,使得在不同的排序需求下,可以灵活选择不同的排序策略。
  • 支付网关
    • 在支付网关中,可以根据用户的选择动态切换支付方式,如使用信用卡、PayPal 或 Apple Pay 等。每种支付方式对应一个策略,用户选择后,系统根据策略类进行处理。

6. 出站链接

7. 站内链接

8. 参考资料

  • Gamma, E., Design Patterns: Elements of Reusable Object-Oriented Software (1994).
  • Freeman, E., Head First Design Patterns (2004).

总结

  • 策略模式允许在运行时选择不同的算法或行为,通过将每种算法封装为独立的策略类,避免了复杂的条件判断语句,并提高了代码的可扩展性。
  • 适用于算法选择、行为变化频繁的场景,如支付方式、排序算法、促销策略等。
  • 虽然增加了类的数量,但其提供的灵活性和代码复用性使得它在需要动态选择算法的系统中非常有效。

如果你有更多问题或希望进一步探讨,欢迎继续交流!🚀