本文主要内容
经典的“策略”模式
文中代码均放在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() |