《流畅的Python》笔记。
本篇主要讲述Python中使用函数来实现策略模式和命令模式,最后总结出这种做法背后的思想。
策略模式如果用面向对象的思想来简单解释的话,其实就是“多态”。父类指向子类,根据子类对同一方法的不同重写,得到不同结果。
下图是经典的策略模式的UML类图:
《设计模式:可复用面向对象软件的基础》一书这样描述策略模式:
定义一系列算法,把它们封装起来,且使它们能相互替换。本模式使得算法可独立于使用它的客户而变化。
下面以一个电商打折的例子来说明策略模式,打折方案如下:
- 有1000及以上积分的顾客,每个订单享5%优惠;
- 同一订单中,每类商品的数量达到20个及以上时,该类商品享10%优惠;
- 订单中的不同商品达10个及以上时,整个订单享7%优惠。
为此我们需要创建5个类:
Order类:订单类,相当于上述UML图中的Context上下文;Promotion类:折扣类的父类,相当于UML图中的Strategy策略类,实现不同策略的共同接口;- 具体策略类:
FidelityPromo,BulkPromo和LargeOrderPromo依次对应于上述三个打折方案。
以下是经典的策略模式在Python中的实现:
from abc import ABC, abstractmethod from collections import namedtuple Customer = namedtuple("Customer", "name fidelity") class LineItem: # 单个商品 def __init__(self, product, quantity, price): self.produce = product self.quantity = quantity self.price = price def total(self): return self.price * self.quantity class Order: # 订单类,上下文 def __init__(self, customer, cart, promotion=None): self.customer = customer self.cart = list(cart) # 形参cart中的元素是LineItem 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 self.promotion is None: discount = 0 else: discount = self.promotion.discount(self) return self.total() - discount class Promotion(ABC): # 策略:抽象基类 @abstractmethod # 抽象方法 def discount(self, order): """返回折扣金额(正值)""" class FidelityPromo(Promotion): # 第一个具体策略 """积分1000及以上的顾客享5%""" def discount(self, order): return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0 class BulkItemPromo(Promotion): # 第二个具体策略 """某类商品为20个及以上时,该类商品享10%优惠""" def discount(self, order): discount = 0 for item in order.cart: if item.quantity >= 20: