设计模式学习笔记(一)

策略者模式
本篇文章参考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))



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值