使用一等函数实现设计模式
这里我们以策略模式来讲解
定义一系列算法, 把他们封装起来, 并且使他们可以相互替换, 可以使算法独立于使用它的客户而变化
主要目的就是为了让任意买家
以任意 打折方案
清空任意购物车
三者任意结合给出最终金额
购物车
包括 订单数组
, 买家
, 打折方案
订单数组
由一系列订单
组成买家
包括买家姓名
,买家积分
打折方案
只有一个折扣
方法, 传入购物车
本身使用类的思路来实现
# -*- 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 = ''
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())
然后我们想一下, 在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 = ''
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)
然后在此基础上, 写一个最佳的策略模式
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)
全部策略
实际上讲的使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