读书笔记:《流畅的Python》第六章 使用一等函数实现设计模式

一些概念

# 策略模式
#     定义一系列算法,把它们一一封装起来,并且使他们可以相互替换,使得算法
#     可以独立于使用它的客户而变化。
# 模板方法
# 访问者模式

# 重构策略模式
#     代码:
#         经典的策略模式.py
#         使用函数实现策略模式.py

# 享元(flyweight)
#     是可共享的对象,可以同时在多个上下文中使用

# 命令模式 : 目的是解耦调用操作的对象(调用者)和提供实现的对象(接收者)

经典的策略模式:电商折扣.py

# 有1000或者以上积分 享受5%折扣
# 同一订单中单个商品数量达到20或者以上,享10%折扣
# 订单中的不同商品达到10个或以上,享7%折扣
# 一个订单只能享受一个折扣


"""上下文:
    把计算委托给不同的算法可互换组件,本例为Order,它会根据不同的算法计算促销折扣
策略:
    实现不同算法的共同接口,本例中Promotion这个抽象类扮演这个角色
具体策略:
    策略的具体子类,fidelityPromo、BulkPromo\LargeOrderPromo是这里实现的三个具体策略"""

# 实现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,promition = None):  # 客户\购物车\促销折扣
        self.customer = customer
        self.cart = cart
        self.promotion = promition

    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: # 策略,抽象基类
    @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 BuckItemPromo(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


if __name__ == '__main__':
    joe = Customer('John Doe',0)
    ann = Customer('Ann Smith',1100)
    cart = [LineItem('banana',4,.5),
            LineItem('apple',10,1.5),
            LineItem('watermellon',5,5.0)]

    print(Order(joe, cart, FidelityPromo()))
    print(Order(ann, cart, FidelityPromo()))

    banana_cart = [LineItem('banana',30,.5),
                   LineItem('apple',10,1.5)]
    print(Order(joe, banana_cart, BuckItemPromo()))

    large_order = [LineItem(str(item_code),1,1.0)
                   for item_code in range(10)]

    print(Order(joe, large_order, LargeOrderPromo()))
    print(Order(joe, cart, LargeOrderPromo()))

















使用函数实现策略模式.py

# 有1000或者以上积分 享受5%折扣
# 同一订单中单个商品数量达到20或者以上,享10%折扣
# 订单中的不同商品达到10个或以上,享7%折扣
# 一个订单只能享受一个折扣


"""上下文:
    把计算委托给不同的算法可互换组件,本例为Order,它会根据不同的算法计算促销折扣
策略:
    实现不同算法的共同接口,本例中Promotion这个抽象类扮演这个角色
具体策略:
    策略的具体子类,fidelityPromo、BulkPromo\LargeOrderPromo是这里实现的三个具体策略"""

# 实现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,promition = None):  # 客户\购物车\促销折扣
        self.customer = customer
        self.cart = cart
        self.promotion = promition

    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: # 策略,抽象基类
    @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 BuckItemPromo(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


if __name__ == '__main__':
    joe = Customer('John Doe',0)
    ann = Customer('Ann Smith',1100)
    cart = [LineItem('banana',4,.5),
            LineItem('apple',10,1.5),
            LineItem('watermellon',5,5.0)]

    print(Order(joe, cart, FidelityPromo()))
    print(Order(ann, cart, FidelityPromo()))

    banana_cart = [LineItem('banana',30,.5),
                   LineItem('apple',10,1.5)]
    print(Order(joe, banana_cart, BuckItemPromo()))

    large_order = [LineItem(str(item_code),1,1.0)
                   for item_code in range(10)]

    print(Order(joe, large_order, LargeOrderPromo()))
    print(Order(joe, cart, LargeOrderPromo()))

















上一篇:第1次任务:购物车程序的面向对象设计


下一篇:决策树挑出好西瓜(基于ID3、CART)