一、策略模式
定义一系列算法,把它们一一封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。
以电商商品计算折扣为例:
- 1000或以上积分,每个订单享5%折扣
- 同一订单中单商品数量达到20个或以上,享10%折扣
- 订单中不同商品达到10个或以上,享7%折扣

如上图:
- 上下文:把一些计算委托给实现不同算法的可互换组件,它提供服务。此示例中。上下文是
Order,它会根据不同算法计算促销折扣 - 策略:实现不同算法的组件共同接口
- 具体策略:“策略”的具体子类 ```python from abc import ABC, abstractmethod from collections import namedtuple
Customer = namedtuple(“Customer”, [“name”, “fidelity”])
class LineItem:
def __init__(self, product: str, quantity: int, price: float):self.product = productself.quantity = quantityself.price = pricedef total(self):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 >
```
