larken

勤奋的人生才有价值

导航

第 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 延伸阅读

 

posted on 2019-03-18 00:12  larken  阅读(207)  评论(0编辑  收藏  举报