策略者模式
本篇文章参考head first 设计模式 和流畅的Python 这俩本书
在平时学习中,我们总是面向实现编程,每一个特定的问题,就专门写一个代码。其实这样实现起来特别特别累,特别是当我在写一些大同小异的代码的时候,一不留神就改错了。所以第一次接触设计模式的时候,大概是在学习流畅的Python的时候,事实上设计模式和数据结构与算法一样,当你写程序写多了,自然想要预先设计自己代码的模式,使自己的编程更加有效率。
所以我们要牢记几个设计原则:
1.找出程序中会变化的方面,然后将其和固定不变的方面相分离。
2.针对接口编程,不针对实现编程
3.多用组合,少用继承
现在想要介绍策略者模式,和观察者模式。
1.考虑这样一个场景,当你要设计一个鸭子对象,各种鸭子,有的游泳戏水,有的咕咕叫,有的呱呱叫,还有的会飞,有的不会飞。那么怎么办呢?
你的第一反应可能是这样,首先定义一个基本的鸭子类,其中定义一些飞行,外观方法,比如Python中这样:
#python 写法
class Duck:
def swim(): 游泳方式
def fly(): 飞行方式
def display(); 外观长相
def quack(); 叫声
可是你有没有想过,如果你的鸭子是一只木头鸭子,它既不会叫也不会飞 ,也不会游泳怎么办?
你可能会想,我可以同样把这只鸭子继承下来,但是我在方法当中重写的时候什么也不干,把它覆盖掉。
但是你有没有想过,这只是一直木头鸭子,如果是金属鸭,玩具鸭等等,每一个鸭子的外观不一样dispaly 都不一样,难道你每一个鸭子都要重写么?
这就让我们思考一个问题,我们是不是应该把经常变化的方法,和不变的方法分开放呢
现在我们就要继续以鸭子为例:
假设除了fly(),quack()这俩种方法以外,所有的鸭子行为都差不多
让我们来看一下策略者模式的鸭子设计方式(java 方法 head first 设计模式当中写的比我好多了)
#python
class Flybehavior():
def fly(self):
pass
from strategy import FlyBehavior
class FlywithWing(FlyBehavior.Flybehavior):#这里我刚开始还是没有改变来自java的习惯,把基本类当成一个接口单独去实现了
def fly(self):
print("I can fly with wing")
from strategy import FlyBehavior
class Flynoway(FlyBehavior.Flybehavior):
def fly(self):
print("I can fly no way!")
from strategy import Flynoway, FlywithWing
class Duck:
def __init__(self):
self.strategy = FlywithWing.FlywithWing()
def fly(self):
self.strategy.fly()
def setfly(self,strategy):
self.strategy =strategy
if __name__ =="__main__":
c = Duck()
c.fly()
c.setfly(Flynoway.Flynoway())
c.fly()
再来一个参考文章 链接
他后面一点基于函数的地方写的有一点点问题,我修正了过来 同样是来自流畅的Python 当时看到鸭子类型 还不是特别理解,直到现在恍然大悟
from collections import namedtuple
Customer = namedtuple('Customer','name fidelity')
class LineItem:
# def __init__(self,customer,carts,promotion =None):
# self.customer = customer
# self.carts = carts
# self.promotion = promotion
def __init__(self,product,number,price):
self.product = product
self.number = number
self.price = price
def total(self):
return self.number*self.price
class Order:
def __init__(self,customer,carts,promotion =None):
self.customer = customer
self.carts = list(carts)
self.promotion = promotion
def total(self):
if not hasattr(self, '__total'):
self.__total = sum(item.total() for item in self.carts)
return self.__total
def due(self):
if self.promotion ==None:
discount = 0
else:
discount = self.promotion(self)#注意这里 传入的一个self参数非常重要!!
return self.total()-discount
def __repr__(self):
fmt = '<Order total:{:.2f}, due:{:.2f}>'
return fmt.format(self.total(),self.due())
# 第一个具体策略
def fidelity_promo(order):
""" 为积分为1000或以上的顾客提供5%的折扣 """
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
# 第二个具体策略
def bulk_item_promo(order):
""" 单个商品为20个或以上时提供10%折扣"""
discount = 0
for item in order.carts:
if item.number >= 20:
discount = item.total() * .1
return discount
# 第三个具体策略
def large_order_promo(order):
""" 订单中的不同商品达到10个或以上时提供%7的折扣"""
distinct_items = {item.product for item in order.carts}
if len(distinct_items) >= 10:
return order.total() * .07
return 0
# 第四个具体策略
prmos = [globals()[name] for name in globals() if name.endswith("_promo") and name !='best_order_promo']
def best_order_promo(order):
return max(promo(order) for promo in prmos)
if __name__ =="__main__":
joe = Customer('John Doe', 0)
ann = Customer('Ann Smith', 1100)
cart = [LineItem('banana', 4, .5),
LineItem('apple', 10, 1.5),
LineItem('watermellon', 5, 5.0)]
print('John: ', Order(joe, cart, best_order_promo))
print('Ann: ', Order(ann, cart, best_order_promo))