美文网首页
设计模式01策略模式

设计模式01策略模式

作者: 极光火狐狸 | 来源:发表于2017-05-12 16:07 被阅读25次

    原始代码模型(全部采用继承)

    代码
    # -.- coding:utf-8 -.-
    from __future__ import print_function
    
    
    class Duck(object):
    
        def __init__(self, *args, **kwargs):
            self.name = '鸭子'
            self._ = '{}{}{}'
    
        def display(self):
            raise NotImplementedError
    
        def _display(self, value):
            value = self._.format(self.name, ': ', value)
            print(value)
            return value
    
        def quack(self):
            return self._display('呱呱叫')
    
        def swim(self):
            return self._display('游泳')
    
    
    class MallardDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(MallardDuck, self).__init__(*args, **kwargs)
            self.name = '绿头鸭'
    
        def display(self):
             return self._display('外观是绿头')
             
    
    class RedheadDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RedheadDuck, self).__init__(*args, **kwargs)
            self.name = '红头鸭'
    
        def display(self):
            return self._display('外观是红头')
    
    
    if __name__ == '__main__':
        mallard_duck = MallardDuck()
        mallard_duck.display()
        mallard_duck.quack()
        print()
        redhead_duck = RedheadDuck()
        redhead_duck.display()
        redhead_duck.quack()
    
    # 显示结果
    绿头鸭: 外观是绿头
    绿头鸭: 呱呱叫
    
    红头鸭: 外观是红头
    红头鸭: 呱呱叫
    
    需求

    现在要求增加一个让鸭子飞的功能。(备注:需求要求很模糊)

    解决办法

    在Duck父类中增加一个fly方法,那么所有的子类都会拥有飞行行为(因为这就是继承)。

    # -.- coding:utf-8 -.-
    from __future__ import print_function
    
    
    class Duck(object):
    
        # 在原来的基础上增加一个fly方法
        def fly(self):
            return self._display('飞行')
    
    
    
    # 增加一个橡皮鸭对象
    class RubberDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RubberDuck, self).__init__(*args, **kwargs)
            self.name = '橡皮鸭'
    
        def display(self):
            return self._display('外观是橡皮')
    
    
    if __name__ == '__main__':
        mallard_duck = MallardDuck()
        mallard_duck.display()
        mallard_duck.quack()
        mallard_duck.fly()
        print()
        redhead_duck = RedheadDuck()
        redhead_duck.display()
        redhead_duck.quack()
        redhead_duck.fly()
        print()
        redhead_duck = RubberDuck()
        redhead_duck.display()
        redhead_duck.quack()
        redhead_duck.fly()
    
    # 显示结果
    绿头鸭: 外观是绿头
    绿头鸭: 呱呱叫
    绿头鸭: 飞行
    
    红头鸭: 外观是红头
    红头鸭: 呱呱叫
    红头鸭: 飞行
    
    橡皮鸭: 外观是橡皮鸭
    橡皮鸭: 呱呱叫
    橡皮鸭: 飞行
    
    延伸出来的问题

    单从功能上来讲,在父类中增加了一个fly方法,那么所有的子类都拥有了fly行为,这是没问题的。但是从业务逻辑的角度来讲,那么并非所有鸭子都能飞(一般像被驯化的家鸭是没有飞行能力了,野鸭一般都能飞,故事中的橡皮鸭不能飞而且叫的声音也不一样,不是呱呱叫而是吱吱叫)。

    另外一种尝试

    采用继承中的一种特性<覆盖/或者叫多态>来让橡皮鸭自己实现自己的功能。

    # -.- coding:utf-8 -.-
    from __future__ import print_function
    
    
    class Duck(object):
    
        def __init__(self, *args, **kwargs):
            self.name = '鸭子'
            self._ = '{}{}{}'
    
        def display(self):
            raise NotImplementedError
    
        def _display(self, value):
            value = self._.format(self.name, ': ', value)
            print(value)
            return value
    
        def fly(self):
            return self._display('飞行')
    
        def quack(self):
            return self._display('呱呱叫')
    
        def swim(self):
            return self._display('游泳')
    
    
    class MallardDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(MallardDuck, self).__init__(*args, **kwargs)
            self.name = '绿头鸭'
    
        def display(self):
            return self._display('外观是绿头')
    
    
    class RedheadDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RedheadDuck, self).__init__(*args, **kwargs)
            self.name = '红头鸭'
    
        def display(self):
            return self._display('外观是红头')
    
    
    class RubberDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RubberDuck, self).__init__(*args, **kwargs)
            self.name = '橡皮鸭'
    
        # 覆盖Duck的quack方法
        def quack(self):
            return self._display('吱吱叫')
    
        # 覆盖Duck的fly方法
        def fly(self):
            return self._display('不能飞行')
    
        def display(self):
            return self._display('外观是橡皮')
    
    
    # 增加诱饵鸭
    class DecoyDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(DecoyDuck, self).__init__(*args, **kwargs)
            self.name = '诱饵鸭'
    
        # 覆盖Duck的quack方法
        def quack(self):
            return self._display('不能叫')
    
        # 覆盖Duck的fly方法
        def fly(self):
            return self._display('不能飞')
    
        def display(self):
            return self._display('外观是诱饵')
    
    
    # 增加模型鸭
    class ModelDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(ModelDuck, self).__init__(*args, **kwargs)
            self.name = '模型鸭'
            
        # 覆盖Duck的quack方法
        def quack(self):
            return self._display('不能叫')
    
        # 覆盖Duck的fly方法
        def fly(self):
            return self._display('不能飞')
    
        def display(self):
            return self._display('外观是模型')
    
    
    if __name__ == '__main__':
        mallard_duck = MallardDuck()
        mallard_duck.display()
        mallard_duck.quack()
        mallard_duck.fly()
        print()
        redhead_duck = RedheadDuck()
        redhead_duck.display()
        redhead_duck.quack()
        redhead_duck.fly()
        print()
        rubber_duck = RubberDuck()
        rubber_duck.display()
        rubber_duck.quack()
        rubber_duck.fly()
        print()
        decoy_duck = DecoyDuck()
        decoy_duck.display()
        decoy_duck.quack()
        decoy_duck.fly()
        print()
        model_duck = ModelDuck()
        model_duck.display()
        model_duck.quack()
        model_duck.fly()
        
    # 查看结果
    绿头鸭: 外观是绿头
    绿头鸭: 呱呱叫
    绿头鸭: 飞行
    
    红头鸭: 外观是红头
    红头鸭: 呱呱叫
    红头鸭: 飞行
    
    橡皮鸭: 外观是橡皮
    橡皮鸭: 吱吱叫
    橡皮鸭: 不能飞行
    
    诱饵鸭: 外观是诱饵
    诱饵鸭: 不能叫
    诱饵鸭: 不能飞
    
    模型鸭: 外观是模型
    模型鸭: 不能叫
    模型鸭: 不能飞
    
    

    组合+继承

    嗯,上面这个尝试确实能解决橡皮鸭不能飞的问题(解决这个问题至少有三种办法:第一种是实现代码都完全在具体的方法中完成,这样就没办法做到代码的复用;第二种是在外部写好函数,相同功能要求的行为调用该函数,但是这种对代码的组织会存在一定的问题,随着项目的不断扩大而变得越来越不容易管理;第三种就是抽象成一个类将类似的实现进行一个合理的归纳。)。目前代码中是有五种鸭子,如果有200种鸭子,其中有15种跟橡皮鸭一样吱吱叫但是要能飞,另外40种跟橡皮鸭一样不能飞行但是要呱呱叫,这种情况该如何复用(每种鸭子类都跟橡皮鸭类一样自己去写一遍实现,我觉得这个坑太大了)?

    像这种情况就是典型的行为分类,将<叫>和<飞>的行为剥离出来,然后根据不同的鸭子属性去给予它不同的能力(这种多重的能力在不同鸭子之间的搭配使用就叫做组合)。

    代码
    # -.- coding:utf-8 -.-
    from __future__ import print_function
    
    
    ################################################################################
    # Display                                                                      #
    ################################################################################
    class Display(object):
    
        def __init__(self):
            self._ = '{}{}{}'
    
        def display(self, name, value):
            value = self._.format(name, ': ', value)
            print(value)
            return value
    
    ################################################################################
    # Ducks                                                                        #
    ################################################################################
    class Duck(object):
    
        _ = '{}{}{}'
    
        def __init__(self, *args, **kwargs):
            self.name = '鸭子'
            self.fly_behavior = None
            self.quack_behavior = None
            self._display = Display().display
    
        def display(self):
            raise NotImplementedError
    
        def fly(self):
            if self.fly_behavior:
                return self.fly_behavior.fly(self.name)
            return self._display(self.name, '飞行')
    
        def quack(self):
            if self.quack_behavior:
                return self.quack_behavior.quack(self.name)
            return self._display(self.name, '呱呱叫')
    
        def swim(self):
            return self._display(self.name, '游泳')
    
        def set_fly_behavior(self, fly_behavior):
            self.fly_behavior = fly_behavior
    
        def set_quack_behavior(self, quack_behavior):
            self.quack_behavior = quack_behavior
    
    
    class MallardDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(MallardDuck, self).__init__(*args, **kwargs)
            self.name = '绿头鸭'
    
        def display(self):
            return self._display(self.name, '外观是绿头')
    
    
    class RedheadDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RedheadDuck, self).__init__(*args, **kwargs)
            self.name = '红头鸭'
    
        def display(self):
            return self._display(self.name, '外观是红头')
    
    
    class RubberDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(RubberDuck, self).__init__(*args, **kwargs)
            self.name = '橡皮鸭'
    
        def quack(self):
            return self._display(self.name, '吱吱叫')
    
        def fly(self):
            return self._display(self.name, '不能飞行')
    
        def display(self):
            return self._display(self.name, '外观是橡皮')
    
    
    class DecoyDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(DecoyDuck, self).__init__(*args, **kwargs)
            self.name = '诱饵鸭'
    
        def quack(self):
            return self._display(self.name, '不能叫')
    
        def fly(self):
            return self._display(self.name, '不能飞')
    
        def display(self):
            return self._display(self.name, '外观是诱饵')
    
    
    class ModelDuck(Duck):
    
        def __init__(self, *args, **kwargs):
            super(ModelDuck, self).__init__(*args, **kwargs)
            self.name = '模型鸭'
    
        def quack(self):
            return self._display(self.name, '不能叫')
    
        def fly(self):
            return self._display(self.name, '不能飞')
    
        def display(self):
            return self._display(self.name, '外观是模型')
    
    
    ################################################################################
    # Quack behaviors                                                              #
    ################################################################################
    class QuackBehavior(object):
    
        def quack(self, *args, **kwargs):
            raise NotImplementedError
    
    
    class Quack(QuackBehavior):
    
        def quack(self, name):
            return Display().display(name, "呱呱叫")
    
    
    class MuteQuack(QuackBehavior):
        def quack(self, name):
            return Display().display(name, "不能叫")
    
    
    class Squeak(QuackBehavior):
        def quack(self, name):
            return Display().display(name, "吱吱叫")
    
    
    class FakeQuack(QuackBehavior):
        def quack(self, name):
            return Display().display(name, "假叫")
    
    
    ################################################################################
    # Fly behaviors                                                                #
    ################################################################################
    class FlyBehavior(object):
        def fly(self, *args, **kwargs):
            pass
    
    
    class FlyWithWings(FlyBehavior):
        def fly(self, name):
            return Display().display(name, "飞行!")
    
    
    class FlyNoWay(FlyBehavior):
        def fly(self, name):
            return Display().display(name, "不能飞!")
    
    
    class FlyRocketPowered(FlyBehavior):
        def fly(self, name):
            return Display().display(name, "坐火箭飞!")
    
    
    if __name__ == '__main__':
        mallard_duck = MallardDuck()
        mallard_duck.display()
        mallard_duck.quack()
        mallard_duck.fly()
    
        print()
        
        mallard_duck = MallardDuck()
        mallard_duck.display()
        mallard_duck.set_quack_behavior(FakeQuack())
        mallard_duck.set_fly_behavior(FlyRocketPowered())
        mallard_duck.quack()
        mallard_duck.fly()
    
    # 显示结果
    绿头鸭: 外观是绿头
    绿头鸭: 呱呱叫
    绿头鸭: 飞行
    
    绿头鸭: 外观是绿头
    绿头鸭: 假叫
    绿头鸭: 坐火箭飞!
    
    解决了什么问题

    在最后__main__中可以看到,通过剥离出两个行为类之后,可以在运行时灵活通过给定不同类来影响它的最终结果。
    这里面的一切都依赖于接口的一致性。

    模式总结

    策略模式强调的是将性质和行为相似的代码封装起来,让它们之间可以相互替换。

    核心理念

    在运行时选择操作(Choosing the operations at Runtime).

    模式类型

    行为模式

    设计原则
    1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
    2. 针对接口编程,而不是针对实现编程。
    3. 多用组合,少用继承。

    参考

    相关文章

      网友评论

          本文标题:设计模式01策略模式

          本文链接:https://www.haomeiwen.com/subject/jhaegttx.html