python设计模式六大原则_[流畅的Python]读书笔记之六设计模式

Python设计模式

Peter Norvig, 对就是他,在'Design Pattern in Dynamic Languages'的演讲中指出,在《设计模式,可复用面向对象软件的基础》一书中有23个模式,其中有16个在动态语言中‘不见了,或者简化了’。

深有感触,之前看一篇文章,里面有C++实现了一个算法,当我想用Python重写的时候,发现需要写的类至少少了三个,而且可以用啥 namedtuple啊, 至于指针返回值,虚函数,基类这些东西完全就是无关的。

看一看作者在书中给的例子:

如果完全按照设计模式来做,需要写代码如下:

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: # the Context

def __init__(self, customer, cart, promotion=None):

self.customer = customer

self.cart = list(cart)

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 = ''

return fmt.format(self.total(), self.due())

class Promotion(ABC): # the Strategy: an Abstract Base Class

@abstractmethod

def discount(self, order):

"""Return discount as a positive dollar amount"""

class FidelityPromo(Promotion): # first Concrete Strategy

"""5% discount for customers with 1000 or more fidelity points"""

def discount(self, order):

return order.total() * .05 if order.customer.fidelity >= 1000 else 0

class BulkItemPromo(Promotion): # second Concrete Strategy

"""10% discount for each LineItem with 20 or more units"""

def discount(self, order):

discount = 0

for item in order.cart:

if item.quantity >= 20:

discount += item.total() * .1

return discount

class LargeOrderPromo(Promotion): # third Concrete Strategy

"""7% discount for orders with 10 or more distinct items"""

def discount(self, order):

distinct_items = {item.product for item in order.cart}

if len(distinct_items) >= 10:

return order.total() * .07

return 0

我才了解ABC(Abstract Base Class),原来Python也是可以可以 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: # the Context

def __init__(self, customer, cart, promotion=None):

self.customer = customer

self.cart = list(cart)

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 = ''

return fmt.format(self.total(), self.due())

def fidelity_promo(order):

"""5% discount for customers with 1000 or more fidelity points"""

return order.total() * .05 if order.customer.fidelity >= 1000 else 0

def bulk_item_promo(order):

"""10% discount for each LineItem with 20 or more units"""

discount = 0

for item in order.cart:

if item.quantity >= 20:

discount += item.total() * .1

return discount

def large_order_promo(order):

"""7% discount for orders with 10 or more distinct items"""

distinct_items = {item.product for item in order.cart}

if len(distinct_items) >= 10:

return order.total() * .07

return 0

把函数直接拿来用,把 order.promotion 变成我们想用的 promotion 策略,然后直接用。

最优折扣

我们甚至可以添加一个 best_promo 函数,来帮顾客最优折扣:

promos = [fidelity_promo, bulk_item_promo, large_order_promo]

def best_promo(order):

"""Select best discount available

"""

return max(promo(order) for promo in promos)

但是这样有个缺点,每次我们如果新加了 promotion 策略,我们都需要把它添加到 promos 列表中。

我们可以用以下办法来生成所有折扣列表:

promos = [globals()[name] for name in globals()

if name.endswith('_promo')

and name != 'best_promo']

globals() 会返回一个字典,找到所有的 promo 函数,但是这里注意我们需要注意,新的策略需要用 _promo 作为结束。

除了和这个办法以外,我们也可以把 promotions 单独放到一个 promotions.py 文件中,然后导入再来构建:

#import promotions

...

promos = [func for name, func in

inspect.getmembers(promotions, inspect.isfunction)]

...

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值