一、策略模式

定义一系列算法,把它们一一封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。

以电商商品计算折扣为例:

  • 1000或以上积分,每个订单享5%折扣
  • 同一订单中单商品数量达到20个或以上,享10%折扣
  • 订单中不同商品达到10个或以上,享7%折扣

策略模式.jpg
如上图:

  • 上下文:把一些计算委托给实现不同算法的可互换组件,它提供服务。此示例中。上下文是Order,它会根据不同算法计算促销折扣
  • 策略:实现不同算法的组件共同接口
  • 具体策略:“策略”的具体子类 ```python from abc import ABC, abstractmethod from collections import namedtuple

Customer = namedtuple(“Customer”, [“name”, “fidelity”])

class LineItem:

  1. def __init__(self, product: str, quantity: int, price: float):
  2. self.product = product
  3. self.quantity = quantity
  4. self.price = price
  5. def total(self):
  6. return self.quantity * self.price

上下文

class Order:

def __init__(self, customer: Customer, cart: [LineItem], promotion=None):
    self.customer = customer
    self.cart = cart
    self.promotion = promotion

def total(self):
    if not hasattr(self, "_total"):
        self._total = sum(item.total() for item in self.cart)
    return self._total

def due(self):
    if not self.promotion:
        discount = 0
    else:
        discount = self.promotion.discount(self)
    return self.total() - discount

def __repr__(self):
    fmt = "<Order total: {:.2f} due: {:.2f}>"
    return fmt.format(self.total(), self.due())

策略:抽象类

class Promotion(ABC):

@abstractmethod
def discount(self, order: Order):
    '''
    返回折扣金额
    :return:
    '''
    pass

第一个具体策略:为积分1000或以上的顾客提供5%折扣

class FidelityPromo(Promotion):

def discount(self, order: Order):
    return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0

第二个具体策略:单个商品为20个或以上时提供10%折扣

class BulkItemPromo(Promotion):

def discount(self, order: Order):
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += order.total() * 0.1
    return discount

第三个具体策略:订单中不同商品的数量达到10个或以上是提供7%折扣

class LargeOrderPromo(Promotion):

def discount(self, order: Order):
    distinct_items = {item.product for item in order.cart}
    return order.total() * 0.07 if len(distinct_items) >= 10 else 0

if name == “main“:

joe = Customer("John Doe", 0)
ann = Customer("Ann Smith", 1100)

cart = [LineItem("banana", 4, 0.5), LineItem("apple", 10, 1.5), LineItem("watermellon", 5, 5.0)]
print(Order(joe, cart, FidelityPromo()))  # < Order total: 42.00 due: 42.00 >
print(Order(ann, cart, FidelityPromo()))  # < Order total: 42.00 due: 39.90 >

banana_cart = [LineItem("banana", 30, 0.5), LineItem("apple", 10, 1.5)]
print(Order(joe, banana_cart, BulkItemPromo())) # < Order total: 30.00 due: 27.00 >

long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]
print(Order(joe, long_order, LargeOrderPromo())) # < Order total: 10.00 due: 9.30 >
print(Order(joe, cart, LargeOrderPromo())) # < Order total: 42.00 due: 42.00 >

```