Fluent Python 3函数 2使用函数实现设计模式

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)  #商品类LineItem的实例的列表
		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): 
		pass #返回折扣金额(正值)

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): 
		if len(order.cart) >= 10: 
			return order.total() * .07 
		return 0

上下文。把一些计算委托给实现不同算法的可互换组件,它提供服务。在这个电商示例中,上下文是 Order,它会根据不同的算法计算促销折扣。

策略。实现不同算法的组件共同的接口。在这个示例中,名为 Promotion 的抽象基类扮演这个角色。

具体策略。“策略”的具体子类。fidelityPromo、BulkPromo 和 LargeOrderPromo 是这里实现的三个具体策略。

对上面的程序运行测试:

if __name__ == '__main__':
	apple = LineItem('apple',20,1.2)
	iphone = LineItem('iphone',1,6000)
	milk = LineItem('milk',10,3)

	gyf = Customer('guoyunfei',1000)
	zz = Customer('zzzz',20)

	cart1 = [iphone]
	cart2 = [apple,milk]

	print(Order(gyf,cart1,promotion=FidelityPromo())) #积分为1000或以上的顾客提供5%折扣 
	print(Order(zz,cart2,promotion=BulkItemPromo())) #单个商品为20个或以上时提供10%折扣

运行结果:

<Order total: 6000.00 due: 5700.00>
<Order total: 54.00 due: 51.60>

2

进行重构,去掉抽象基类,把具体策略由类改为函数。

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)  #商品类LineItem的实例的列表
		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(self) 
		return self.total() - discount 
	def __repr__(self): 
		fmt = '<Order total: {:.2f} due: {:.2f}>' 
		return fmt.format(self.total(), self.due()) 

	# 第一个具体策略 
	"""为积分为1000或以上的顾客提供5%折扣""" 
def discount1(order): 
	return order.total() * .05 if order.customer.fidelity >= 1000 else 0

	# 第二个具体策略 
	"""单个商品为20个或以上时提供10%折扣""" 
def discount2(order): 
	discount = 0 
	for item in order.cart:
		if item.quantity >= 20: 
			discount += item.total() * .1 
	return discount

	 # 第三个具体策略 
	"""订单中的不同商品达到10个或以上时提供7%折扣""" 
def discount3(order): 
	if len(order.cart) >= 10: 
		return order.total() * .07 
	return 0


if __name__ == '__main__':
	apple = LineItem('apple',20,1.2)
	iphone = LineItem('iphone',1,6000)
	milk = LineItem('milk',10,3)

	gyf = Customer('guoyunfei',1000)
	zz = Customer('zzzz',20)

	cart1 = [iphone]
	cart2 = [apple,milk]

	print(Order(gyf,cart1,promotion=discount1))  #积分为1000或以上的顾客提供5%折扣 
	print(Order(zz,cart2,promotion=discount2))   #单个商品为20个或以上时提供10%折扣

运行结果:

<Order total: 6000.00 due: 5700.00>
<Order total: 54.00 due: 51.60>

3

系统选择最佳促销折扣策略

#创建包含全部折扣函数的列表
discount_list = [discount1,discount2,discount3]

 discount_list 代替折扣方法传入 Order。

对 Orde r中 due方法进行修改

def due(self): 
    if len(self.promotion) == 0: 
		discount = 0 
	else:
		discount = max(d(self) for d in self.promotion) 
	return self.total() - discount 

实际中,应该定义选择最佳策略的函数,然后把选择结果传给 Order 构造方法,如:

discount_list = [discount1,discount2,discount3]

def best_promo(order): 
	"""选择可用的最佳折扣 """ 
	return max(d(order) for d in discount_list)

但这里如果要改的话,折扣方法也需要改,略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值