python高级(六)——用一等函数实现设计模式

本文主要内容

经典的“策略”模式

 

python高级——目录

文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

 

经典的“策略”模式

'''
    经典的策略模式:
        封装一系列可以互相替代的算法,使得算法可以独立与使用它的客户而变化。


    假设当代商城某服装店有以下三种打折规则:
        1、对于会员,全部商品8.5折
        2、同一件商品买两件及以上,除第一件外,剩余的7.5折
        3、买上5件不同商品,全部商品打8折
    三种规则只能享受一个。
'''


from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        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):
        ''':returns 计算折扣'''


class VipPromo(Promotion):  # 会员折扣
    """:returns 会员8.5折"""

    def discount(self, order):
        return order.total() * .15 if order.customer.vip  else 0


class TwoPromo(Promotion):  # 第二个
    ''':returns 同一件衣服两件以上,第二件及之后的7.5折'''

    def discount(self, order):
        discount = 0
        for item in order.clothing:
            if item.quantity >= 2:
                discount += (item.total() - item.price) * .25
        return discount


class FivePromo(Promotion):  # 5种以上
    """ :returns 买5种不同服装以上,每件8折"""

    def discount(self, order):
        distinct_items = {item.name for item in order.clothing}
        if len(distinct_items) >= 5:
            return order.total() * .2
        return 0


if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo()))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo())) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo())) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
'''
    下面使用函数完成"经典"策略
'''

from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        return self.__total

    def due(self):
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion(self)
        return self.total() - discount

    def __repr__(self):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())



def VipPromo(order):  # 会员折扣
    return order.total() * .15 if order.customer.vip  else 0


def TwoPromo(order):  # 第二个
    discount = 0
    for item in order.clothing:
        if item.quantity >= 2:
            discount += (item.total() - item.price) * .25
    return discount


def FivePromo(order):  # 5种以上
    distinct_items = {item.name for item in order.clothing}
    if len(distinct_items) >= 5:
        return order.total() * .2
    return 0



if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo)) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo)) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
    promos = [VipPromo, TwoPromo, FivePromo]


    def best_stratety(order):
        return max(promo(order) for promo in promos)


    print(Order(joe, clothing, best_stratety))   # <Order total: 2160.00 due: 1728.00>  自动选择最优的策略
'''
    使用globals函数找出当前的全局号。其返回的是字典格式
'''
promos = [globals()[name] for name in globals()
              if name.endswith("Promo")]

    print(promos)   #  找到了三个策略函数 [<function FivePromo at 0x10c363b70>, <function TwoPromo at 0x10c363ae8>, <function VipPromo at 0x10abd3048>]

    def best_stratety(order):
        return max(promo(order) for promo in promos)

print(Order(ann, clothing, best_stratety))  #<Order total: 2160.00 due: 1728.00>
'''
   我们可以创建一个类,管理所有命令,并且将其实例重写为可调用对象
'''

class MacroCommand:
    def __init__(self, commands):
        self.commands = list(commands)

    def __call__(self):
        for command in self.commands:
            command()

 

python高级系列文章目录

python高级——目录

 

posted @ 2018-03-06 19:12  廖Sir  阅读(231)  评论(0编辑  收藏  举报