第 6 章 使用一等函数实现设计模式
# 《流畅的Python》读书笔记 # 第6章 使用一等函数实现设计模式 # 虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用。 # 6.1 案例分析:重构“策略”模式 # 如果合理利用作为一等对象的函数,某些设计模式可以简化,“策略”模式就是其中一个很好的例子。 # 本节接下来的内容中将说明“策略”模式,并使用《设计模式:可复用面向对象软件的基础》一书中所述的“经典”结构实现它。 # 如果你熟悉这个经典模式,可以跳到 6.1.2 节,了解如何使用函数重构代码来有效减少代码行数。 # 6.1.1 经典的“策略”模式 # 示例 6-1 实现Order类,支持插入式折扣策略 from abc import ABC,abstractmethod from collections import namedtuple Customer=namedtuple('Customer','name fidelity') class LineItem: def __init__(self,product,quantity,price): self.product=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) 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 def __repr__(self): fmt='<Order total:{:.2f} due:{:.2f}>' return fmt.format(self.total(),self.due()) class Promotion(ABC): @abstractmethod def discount(self,order): """"返回折扣金额(正值)""" class FidelityPromo(Promotion): """为积分为1000或以上的顾客提供5%折扣""" def discount(self,order): return order.total()*.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: discount += item.total()* .1 return discount class LargeOrderPromo(Promotion): """"订单中的不同商品达到10个或以上时提供7%折扣""" def discount(self,order): distinct_items={item.product for item in order.cart} if len(distinct_items) >= 10: return order.total()* .07 return 0 # 示例 6-2 使用不同促销折扣的Order类示例 joe=Customer('John Doe',0) #joe 的积分是0 ann=Customer('Ann Smith',1100) #ann 的积分是1100。 cart=[ LineItem('banana',4,.5), #有三个商品的购物车。 LineItem('apple',10,1.5), LineItem('watermellon',5,5.0) ] print(Order(joe,cart,FidelityPromo())) #fidelityPromo 没给 joe 提供折扣。 #<Order total:42.00 due:42.00> print(Order(ann,cart,FidelityPromo())) #ann 得到了5%折扣,因为她的积分超过 1000。 #<Order total:42.00 due:39.90> banana_cart=[ LineItem('banana',30,.5), #banana_cart中有30把香蕉和10个苹果。 LineItem('apple',10,1.5) ] print(Order(joe,banana_cart,BulkItemPromo())) #BulkItemPromo为joe购买的香蕉优惠了1.50美元。 #<Order total:30.00 due:28.50> long_order=[ LineItem(str(item_code),1,1.0) #long_order中有10个不同的商品,每个商品的价格为1.00美元。 for item_code in range(10) ] print(Order(joe,long_order,LargeOrderPromo())) #LargerOrderPromo 为 joe 的整个订单提供了 7% 折扣。 #<Order total:10.00 due:9.30> print(Order(joe,cart,LargeOrderPromo())) #<Order total:42.00 due:42.00> # 6.1.2 使用函数实现“策略”模式 # 示例 6-3 Order 类和使用函数实现的折扣策略 # 示例 6-4 使用函数实现的促销折扣的 Order 类示例 # 6.1.3 选择最佳策略:简单的方式 # 示例 6-5 best_promo 函数计算所有折扣,并返回额度最大的 # 示例 6-6 best_promo 迭代一个函数列表,并找出折扣额度最大的 # 6.1.4 找出模块中的全部策略 # 示例 6-7 内省模块的全局命名空间,构建 promos 列表 # 示例 6-8 内省单独的 promotions 模块,构建 promos 列表 # 6.2 “命令”模式 # 示例 6-9 MacroCommand 的各个实例都在内部存储着命令列表 # 6.3 本章小结 # 6.4 延伸阅读