《设计模式:可复用面向对象软件的基础》一书中有23个设计模式,其中有16个在动态语言中"不见了或者简化了"。作为动态语言之一的Python, 我们可以利用一等函数简化其中的某些设计模式,本章主要介绍如何使用一等函数重构”策略“模式(关于何为策略模式,可参考策略设计模式)。
用户购置商品,根据不同条件(用户会员积分、单类商品数量、购买的不同商品种类数量),享有不同的优惠策略,最后结算扣除优惠后应该支付的金额。
实体包括:
(1)如果用户积分大于1000,享受5%优惠
(2)单类商品为20个及以上时,享受10%折扣
(3)购买的不同商品种类数量达到3个或以上,享受7%折扣
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 12:31
# @Author : Maple
# @File : 00-相关背景知识.py
# @Software: PyCharm
def fun1(a,b):
return a + b
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def reading(self):
pass
RATIO = 1.2
if __name__ == '__main__':
g = globals()
# 获取当前模块的相关信息(包名,模块路径,模块包含的函数,类等)
print(g) # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018405083DC0>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'D:/01-study/python/fluent_python/06-设计模式/00-相关背景知识.py', '__cached__': None, 'fun1': , 'Person': , 'RATIO': 1.2, 'g': {...}}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/22 22:16
# @Author : Maple
# @File : promotions.py
# @Software: PyCharm
import inspect
import promotions
"""
获取当前模块包含的所有函数
"""
def f1():
pass
def f2():
pass
if __name__ == '__main__':
print(promotions) #
pros = [func for name,func in inspect.getmembers(promotions,inspect.isfunction)]
print(pros) # [, ]
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 9:48
# @Author : Maple
# @File : 01-策略模式传统写法.py
# @Software: PyCharm
from abc import ABC, abstractmethod
from collections import namedtuple
# 顾客具名元组
Customer = namedtuple('Customer','name fidelity')
# # 定义商品类
class Item:
def __init__(self,product,quantity,price):
"""
:param product: 商品名称
:param quantity: 商品数量
:param price: 商品单价
"""
self.product = product
self.quantity = quantity
self.price = price
def totol(self):
"""
:return:订单总费用
"""
return self.quantity * self.price
# 定义上下文
class Order:
def __init__(self,customer,cart,promotion=None):
"""
:param customer: 顾客
:param cart: 购物车
:param promotion: 优惠策略
"""
self.customer = customer
self.cart = cart
self.promotion = promotion
def total(self):
"""
:return:顾客订单打折之前的总费用
"""
if not hasattr(self,'__total'):
self.__total = sum(item.totol() for item in self.cart)
return self.__total
def due(self):
"""
:return:顾客最终支付的费用
"""
if self.promotion is None:
return self.total()
return self.total() - self.promotion.discount(self)
def __repr__(self):
fmt = ''
return fmt.format(self.total(),self.due())
# 定义优惠策略的基类
class BasePromotion(ABC):
@abstractmethod
def discount(self,order):
"""返回折扣金额"""
# 具体策略1:积分优惠策略
class FidelityPromo(BasePromotion):
"""如果积分大于1000,享受5%优惠"""
def discount(self,order):
if order.customer.fidelity > 1000:
return order.total() * 0.05
else:
return 0
# 具体策略2
class BulkItempromo(BasePromotion):
"""单个商品为20个及以上时,提供10%折扣"""
def discount(self,order):
discount = 0
for item in order.cart:
if item.quantity >= 10:
discount += item.totol()* 0.1
return discount
# 具体策略3
class LargetOrderPromo(BasePromotion):
"""购物车中不同商品种类数量达到3个或以上提供7%折扣"""
def discount(self,order):
discount = 0
# 获取购物车中所有不同的商品
products = {item.product for item in order.cart}
if len(products) >=3:
discount += order.total() * 0.07
return discount
if __name__ == '__main__':
#1. 策略1示例
cus1 = Customer('Maple',2000) # 用户积分大于1000,享受5%优惠
cart1=[Item('banana',20,2.0),Item('apple',10,1.0)]
p1 = FidelityPromo()
o1 = Order(cus1,cart1,p1)
print(o1) # 47.5 = (40 + 10 - 50 *0.05)
# 2. 策略2示例
cus2 = Customer('Jack',880)
cart2= [Item('Book',30,1.0),Item('Radio',5,1.0)] # Book订单超过20个,提供10%折扣
p2 = BulkItempromo()
o2 = Order(cus2,cart2,p2)
print(o2) # 32.00 = (30 -30 * 0.1) + 5
# 策略3示例
cus3 = Customer('Mick', 500)
cart3 = [Item('Phone', 5, 2.0), Item('Water', 5, 1.0),Item('ring',20,2)] #购物车不同商品达到3个.提供7%折扣
p3 = LargetOrderPromo()
o3 = Order(cus3, cart3, p3)
print(o3) # 51.15> = (40 + 10 - 50 *0.05)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 11:25
# @Author : Maple
# @File : 02-策略模式函数写法.py
# @Software: PyCharm
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 9:48
# @Author : Maple
# @File : 01-策略模式传统写法.py
# @Software: PyCharm
from abc import ABC, abstractmethod
from collections import namedtuple
# 顾客具名元组
Customer = namedtuple('Customer','name fidelity')
# 定义商品类
class Item:
def __init__(self,product,quantity,price):
"""
:param product: 商品名称
:param quantity: 商品数量
:param price: 商品单价
"""
self.product = product
self.quantity = quantity
self.price = price
def totol(self):
"""
:return:订单总费用
"""
return self.quantity * self.price
# 定义上下文(订单类)
class Order:
def __init__(self,customer,cart,promotion=None):
"""
:param customer: 顾客
:param cart: 购物车
:param promotion: 优惠策略
"""
self.customer = customer
self.cart = cart
self.promotion = promotion
def total(self):
"""
:return:顾客订单打折之前的总费用
"""
if not hasattr(self,'__total'):
self.__total = sum(item.totol() for item in self.cart)
return self.__total
def due(self):
"""
:return:顾客最终支付的费用
"""
if self.promotion is None:
return self.total()
return self.total() - self.promotion(self)
def __repr__(self):
fmt = ''
return fmt.format(self.total(), self.due())
# 具体策略1:积分优惠策略
def FidelityPromo(order):
"""如果积分大于1000,享受5%优惠"""
if order.customer.fidelity > 1000:
return order.total() * 0.05
else:
return 0
# 具体策略2
def BulkItempromo(order):
"""单个商品为20个及以上时,提供10%折扣"""
discount = 0
for item in order.cart:
if item.quantity >= 10:
discount += item.totol()* 0.1
return discount
# 具体策略3
def LargetOrderPromo(order):
"""购物车中不同商品种类数量达到3个或以上提供7%折扣"""
discount = 0
# 获取购物车中所有不同的商品
products = {item.product for item in order.cart}
if len(products) >=3:
discount += order.total() * 0.07
return discount
if __name__ == '__main__':
#1. 策略1示例
cus1 = Customer('Maple',2000)# 用户积分大于1000,享受5%优惠
cart1=[Item('banana',20,2.0),Item('apple',10,1.0)]
o1 = Order(cus1,cart1,FidelityPromo)
print(o1) # 47.5 = (40 + 10 - 50 *0.05)
# 2. 策略2示例
cus2 = Customer('Jack',880)
cart2= [Item('Book',30,1.0),Item('Radio',5,1.0)] #Book订单超过20个,提供10%折扣
o2 = Order(cus2,cart2,BulkItempromo)
print(o2) # 32.00 = (30 -30 * 0.1) + 5
# 策略3示例
cus3 = Customer('Mick', 500)
cart3 = [Item('Phone', 5, 2.0), Item('Water', 5, 1.0),Item('ring',20,2)] #购物车不同商品达到3个.提供7%折扣
o3 = Order(cus3, cart3, LargetOrderPromo)
print(o3) # 51.15> = (40 + 10 - 50 *0.05)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 11:34
# @Author : Maple
# @File : 03-策略模式函数写法-最优策略.py
# @Software: PyCharm
"""
如何自动选择最优策略?
"""
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 11:25
# @Author : Maple
# @File : 02-策略模式函数写法.py
# @Software: PyCharm
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/27 9:48
# @Author : Maple
# @File : 01-策略模式传统写法.py
# @Software: PyCharm
from abc import ABC, abstractmethod
from collections import namedtuple
# 顾客具名元组
Customer = namedtuple('Customer','name fidelity')
# 定义商品类
class Item:
def __init__(self,product,quantity,price):
"""
:param product: 商品名称
:param quantity: 商品数量
:param price: 商品单价
"""
self.product = product
self.quantity = quantity
self.price = price
def totol(self):
"""
:return:订单总费用
"""
return self.quantity * self.price
# 定义上下文(订单类)
class Order:
def __init__(self,customer,cart,promotion=None):
"""
:param customer: 顾客
:param cart: 购物车
:param promotion: 优惠策略
"""
self.customer = customer
self.cart = cart
self.promotion = promotion
def total(self):
"""
:return:顾客订单打折之前的总费用
"""
if not hasattr(self,'__total'):
self.__total = sum(item.totol() for item in self.cart)
return self.__total
def due(self):
"""
:return:顾客最终支付的费用
"""
if self.promotion is None:
return self.total()
return self.total() - self.promotion(self)
def __repr__(self):
fmt = ''
return fmt.format(self.total(), self.due())
# 具体策略1:积分优惠策略
def FidelityPromo(order):
"""如果积分大于1000,享受15%优惠"""
if order.customer.fidelity > 1000:
return order.total() * 0.15
else:
return 0
# 具体策略2
def BulkItemPromo(order):
"""单个商品为20个及以上时,提供10%折扣"""
discount = 0
for item in order.cart:
if item.quantity >= 10:
discount += item.totol()* 0.1
return discount
# 具体策略3
def LargetOrderPromo(order):
"""购物车中不同商品种类数量达到3个或以上提供7%折扣"""
discount = 0
# 获取购物车中所有不同的商品
products = {item.product for item in order.cart}
if len(products) >=3:
discount += order.total() * 0.07
return round(discount,2)
# 最优策略
def optimization_strategy(order):
"""
:param order: 订单类
:return:最优策略和最大折扣
"""
# 手动定义所有优惠策略
promos = [FidelityPromo,BulkItemPromo,LargetOrderPromo]
p_final = None
discount_final = 0
for p in promos:
discount = p(order)
if discount > discount_final:
discount_final = discount
p_final = p
return (p_final,discount_final)
# 最优策略-获取当前模块所有策略的另外一种方式
def optimization_strategy2(order):
# globals返回一个字典,表示当前的全局符号表
promos = [globals()[name] for name in globals()
if name.endswith('Promo')]
p_final = None
discount_final = 0
for p in promos:
discount = p(order)
if discount > discount_final:
discount_final = discount
p_final = p
return (p_final, discount_final)
if __name__ == '__main__':
#1. 最优策略示例1
cus1 = Customer('Maple',2000)# 用户积分大于1000,享受15%(注意:为了测试,数值从5%调整到15%)优惠
cart1=[Item('banana',20,2.0),Item('apple',10,1.0)]
o1 = Order(cus1,cart1,FidelityPromo)
print(optimization_strategy(o1)) # (, 7.5)
print(optimization_strategy2(o1)) # (, 7.5)
print('=====================================================')
# 2. 最优策略示例2
cus2 = Customer('Jack',880)
cart2= [Item('Book',30,1.0),Item('Radio',5,1.0)] #Book订单超过20个,提供10%折扣
o2 = Order(cus2,cart2,BulkItemPromo)
print(optimization_strategy(o2)) # (, 3.0)
print(optimization_strategy2(o2)) # (, 3.0)
print('=====================================================')
# 3. 最优策略示例3
cus3 = Customer('Mick', 300)
cart3 = [Item('Phone', 5, 2.0), Item('Water', 5, 1.0),Item('ring',8,2)] #购物车不同商品达到3个.提供7%折扣
o3 = Order(cus3, cart3, LargetOrderPromo)
print(optimization_strategy(o3)) # (, 2.17)
print(optimization_strategy2(o3)) # (, 2.17)