用函数实现设计模式

符合模式不代表做得对。          ------Ralph Johnson《设计模式:可复用面向对象软件的基础》

案例分析:重构策略模式

利用一等对象的函数,能够使得某些设计模式得以简化。策略模式是个很经典的例子,能够用函数重构它来有效的精简代码。

经典的策略模式

摘自《流畅的python》

淘宝、天猫的购物功能就可以使用策略模式,用户购买商品到购物车,然后系统后台根据不同的策略给予用户一定的回扣。

假定有如下折扣规则:

* 用户积分在1000及以上,每个订单享受5%折扣

* 同一订单中,单个商品的价格达到20个及以上,享受10%折扣

* 订单中的不同商品达到10个或以上,享受7%折扣

为方便起见,不妨假定用户只能享受一种折扣。

上下文

  把一些计算委托给实现不同算法的可互换组件,即Order

策略

  实现不同算法的共同接口,即Promotion

具体策略

  具体的不同算法,即fidelityPromo,BulkPromo,LargeOrderPromo

下面看代码

  1 #导入抽象基类、抽奖方法
  2 from abc import ABC, abstractmethod
  3 #具名元组
  4 from collections import namedtuple
  5 Customer = namedtuple('Customer', 'name fidelity')
  6 
  7 class LineItem:
  8         """
  9         单件商品
 10         """
 11     def __init__(self, product, quantity, price):
 12         self.product = product
 13         self.quantity = quantity
 14         self.price = price
 15 
 16     def total(self):
 17         return self.price * self.quantity
 18 
 19 class Order:
 20     def __init__(self, customer, cart, promotion):
 21         self.customer = customer
 22         self.cart = list(cart)
 23         self.promotion = promotion
 24 
 25     def total(self):
 26         if not hasattr(self, '__total'):
 27             self.__total = sum(item.total() for item in self.cart)
 28         return self.__total
 29 
 30     def due(self):
 31         if self.promotion is None:
 32             discount = 0
 33         else:
 34             #discount = self.promotion.discount(self)
 35             discount = self.promotion(self)
 36         return self.total() - discount
 37 
 38     def __repr__(self):
 39         fmt = '<Order total: {:.2f} due: {:.2f}>'
 40         return fmt.format(self.total(), self.due())
 41 
 42 #抽象类
 43 class Promotion(ABC):
 44     @abstractmethod
 45     def discount(self, order):
 46         """
 47         返回折扣金额
 48         """
 49         pass
 50 
 51 class FidelPromotion(Promotion):
 52     """
 53     为积分1000及以上的顾客提供5%的折扣
 54     """
 55     def discount(self, order):
 56         return order.total()*0.05 if order.customer.fidelity >= 1000 else 0
 57 
 58 
 59 class BulkItemPromotion(Promotion):
 60     """
 61     单个商品为20个及以上提供10%的折扣
 62     """
 63     def discount(self, order):
 64         discount = 0
 65         for item in order.cart:
 66             if item.quantity >= 20:
 67                 discount += item.total()*0.1
 68         return discount
 69 
 70 class LargeOrderPromotion(Promotion):
 71     """
 72     订单中的不同商品达到10个及以上时提供7%折扣
 73     """
 74     def discount(self, order):
 75         itemset = set(item.product for item in order.cart)
 76         #print(itemset)
 77         return order.total()*0.07 if len(itemset) >= 10 else 0
 78 
 79 def fidelity_promotion(order):
 80     """
 81     为积分1000及以上的顾客提供5%的折扣
 82     """
 83     return order.total()*0.05 if order.customer.fidelity >= 1000 else 0
 84 
 85 
 86 def bulkitem_promotion(order):
 87     """
 88     单个商品为20个及以上提供10%的折扣
 89     """
 90     discount = 0
 91     for item in order.cart:
 92         if item.quantity >= 20:
 93             discount += item.total()*0.1
 94     return discount
 95 
 96 def largeorder_promotion(order):
 97     """
 98     订单中的不同商品达到10个及以上时提供7%折扣
 99     """
100     itemset = set(item.product for item in order.cart)
101     #print(itemset)
102     return order.total()*0.07 if len(itemset) >= 10 else 0
103 
104 joe = Customer('John Doe', 0)
105 ann = Customer('Ann Smith', 1100)
106 cart = [
107     LineItem('banana', 4, .5),
108     LineItem('apple', 10, 1.5),
109     LineItem('watermellon', 5, 5.0)
110 ]
111 
112 print(Order(joe, cart, FidelPromotion()))
113 print(Order(ann, cart, FidelPromotion()))

Promotion定义为抽奖类,使用@abstractmethod修饰discount方法,所以子类FidelityPromotion,BulkItemPromotion,LargeOrderPromotion必须要实现discount方法。

使用函数实现策略模式

在上面的每个策略都是一个类,且只实现了discount一个方法,而且没有实例属性(如果有,可以考虑闭包),因此我们可以定义函数取代上面的策略类。

 1 def fidelity_promotion(order):
 2     """
 3     为积分1000及以上的顾客提供5%的折扣
 4     """
 5     return order.total()*0.05 if order.customer.fidelity >= 1000 else 0
 6 
 7 
 8 def bulkitem_promotion(order):
 9     """
10     单个商品为20个及以上提供10%的折扣
11     """
12     discount = 0
13     for item in order.cart:
14         if item.quantity >= 20:
15             discount += item.total()*0.1
16     return discount
17 
18 def largeorder_promotion(order):
19     """
20     订单中的不同商品达到10个及以上时提供7%折扣
21     """
22     itemset = set(item.product for item in order.cart)
23     #print(itemset)
24     return order.total()*0.07 if len(itemset) >= 10 else 0

可以看出,使用函数的方式重构策略模式,代码行数减少了,而且使用起来也更方便些。

1 print(Order(joe, cart, fidelity_promotion))
2 print(Order(ann, cart, fidelity_promotion))
3 
4 print(Order(joe, banana_cart, bulkitem_promotion))

 

转载于:https://www.cnblogs.com/forwardfeilds/p/10471975.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值