使用一等函数实现设计模式
这里我们以策略模式来讲解
定义一系列算法, 把他们封装起来, 并且使他们可以相互替换, 可以使算法独立于使用它的客户而变化
主要目的就是为了让任意买家
以任意 打折方案
清空任意购物车
三者任意结合给出最终金额
购物车
包括订单数组
,买家
,打折方案
订单数组
由一系列订单
组成买家
包括买家姓名
,买家积分
打折方案
只有一个折扣
方法, 传入购物车
本身
这是购物车
的类图
目录
1. 用类实现购物车策略模式
使用类的思路来实现
# -*- coding: utf-8 -*-
from collections import namedtuple
from abc import abstractmethod
# 具名元组
Customer = namedtuple('Customer', 'name, credits')
class ShopCart(object):
"""购物车"""
def __init__(self, orders, customer, promotion):
"""
:type promotion: Promotion
:type orders: Order
"""
self._orders = orders
self._customer = customer
self._promotion = promotion
@property
def customer(self):
return self._customer
@property
def orders(self):
return self._orders
def total(self):
if not hasattr(self, '_total'):
self._total = sum([item.total() for item in self.orders])
return self._total
def due(self):
if self._promotion:
return self.total() - self._promotion.discount(self)
return self.total()
def __repr__(self):
fmt = '<total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
class Order(object):
def __init__(self, production, quantity, price):
self._production = production
self._quantity = quantity
self._price = price
@property
def production(self):
return self._production
@property
def quantity(self):
return self._quantity
@property
def price(self):
return self._price
def total(self):
return self.quantity * self.price
class Promotion(object):
"""折扣父类"""
@abstractmethod
def discount(self, shop_cart):
"""
:type shop_cart: ShopCart
"""
class GoodCustomerPromotion(Promotion):
"""1000分以上5%折扣"""
def __init__(self):
super(GoodCustomerPromotion, self).__init__()
def discount(self, shop_cart):
if shop_cart.customer.credits >= 1000:
return shop_cart.total() * .05
return 0
class SigletonProductionPromotion(Promotion):
"""单个商品20个以上 10%折扣"""
def __init__(self):
super(SigletonProductionPromotion, self).__init__()
def discount(self, shop_cart):
result = 0
for item in shop_cart.orders:
if item.production > 20:
result += (item.quantity * item.price) * 0.1
return result
class ManyDifferentProductionPromotion(Promotion):
"""不同商品种类10个以上, 给予7%折扣"""
def __init__(self):
super(ManyDifferentProductionPromotion, self).__init__()
def discount(self, shop_cart):
if len(shop_cart.orders) >= 7:
return shop_cart.total() * .07
return 0
# 三个顾客
customer_william = Customer('william', 2000)
customer_zhang = Customer('张冠举', 0)
customer_long = Customer('龙斌', 0)
# 两种购物车
orders_normal = [Order('香蕉', 4, .5), Order('苹果', 10, 1.5), Order('西瓜', 5, 5.0)]
orders_sigleton= [Order('香蕉', 30, .5), Order('苹果', 10, 1.5)]
orders_different = [Order(str(i), 1, 10) for i in range(10)]
print ShopCart(orders_normal, customer_zhang, GoodCustomerPromotion())
print ShopCart(orders_normal, customer_long, GoodCustomerPromotion())
print ShopCart(orders_normal, customer_william, GoodCustomerPromotion())
print ShopCart(orders_sigleton, customer_william, SigletonProductionPromotion())
print ShopCart(orders_different, customer_william, ManyDifferentProductionPromotion())
执行结果
2. 用一等函数实现购物车的策略模式
然后我们想一下, 在python种, 方法也是对象啊, 上面的那些折扣对象不就是用了一个传入ShopCart
对象,返回折扣的方法吗? 那我们完全可以把这些折扣对象写成方法, 然后购物车种拿到这些方法不就行了, 如下:
# -*- coding: utf-8 -*-
from collections import namedtuple
from abc import abstractmethod
Customer = namedtuple('Customer', 'name, credits')
class ShopCart(object):
"""购物车"""
def __init__(self, orders, customer, promotion):
"""
:type promotion: Promotion
:type orders: Order
"""
self._orders = orders
self._customer = customer
self._promotion = promotion
@property
def customer(self):
return self._customer
@property
def orders(self):
return self._orders
def total(self):
if not hasattr(self, '_total'):
self._total = sum([item.total() for item in self.orders])
return self._total
def due(self):
if self._promotion:
return self.total() - self._promotion(self)
return self.total()
def __repr__(self):
fmt = '<total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
class Order(object):
def __init__(self, production, quantity, price):
self._production = production
self._quantity = quantity
self._price = price
@property
def production(self):
return self._production
@property
def quantity(self):
return self._quantity
@property
def price(self):
return self._price
def total(self):
return self.quantity * self.price
def GoodCustomerPromotion(shop_cart):
"""1000分以上5%折扣"""
if shop_cart.customer.credits >= 1000:
return shop_cart.total() * .05
return 0
def SigletonProductionPromotion(shop_cart):
result = 0
for item in shop_cart.orders:
if item.production > 20:
result += (item.quantity * item.price) * 0.1
return result
def ManyDifferentProductionPromotion(shop_cart):
if len(shop_cart.orders) >= 7:
return shop_cart.total() * .07
return 0
# 三个顾客
customer_william = Customer('william', 2000)
customer_zhang = Customer('张冠举', 0)
customer_long = Customer('龙斌', 0)
# 两种购物车
orders_normal = [Order('香蕉', 4, .5), Order('苹果', 10, 1.5), Order('西瓜', 5, 5.0)]
orders_sigleton= [Order('香蕉', 30, .5), Order('苹果', 10, 1.5)]
orders_different = [Order(str(i), 1, 10) for i in range(10)]
print ShopCart(orders=orders_normal, customer=customer_zhang, promotion=GoodCustomerPromotion)
print ShopCart(orders=orders_normal, customer=customer_long, promotion=GoodCustomerPromotion)
print ShopCart(orders=orders_normal, customer=customer_william, promotion=GoodCustomerPromotion)
print ShopCart(orders=orders_sigleton, customer=customer_william, promotion=SigletonProductionPromotion)
print ShopCart(orders=orders_different, customer=customer_william, promotion=ManyDifferentProductionPromotion)
执行结果
3. 最佳的策略模式
然后在此基础上, 写一个最佳的策略模式
def best_promotion(shop_car):
return max([promotion(shop_car) for promotion in [GoodCustomerPromotion, SigletonProductionPromotion, ManyDifferentProductionPromotion]])
print ShopCart(orders=orders_normal, customer=customer_william, promotion=best_promotion)
4. 全部策略
全部策略
实际上讲的使module内部
和外部
得到module中的属性
先说在内部得到, 可使用globals()
globals
, 代表的使当前的全局符号表
可以这样写
# 找出该模块中所有的策略
all_promos = [globals()[name] for name in globals().keys() if name.endswith('Promotion')]
print all_promos
当然, 在当前的module中当然不能使用globals()来获取别的module中的属性
可以使用inspect模块, 在同目录下创建一个新的文件
import inspect
import test
pomoros = [func_name for func_name, func in inspect.getmembers(old_test_01, inspect.isfunction) if func_name.endswith('Promotion')]
print pomoros
执行结果