• 设计模式(一)策略模式


    策略模式的应用实例 - 鸭子开发


    假设一个鸭子实例,要求各种各样的鸭子会游泳、会呱呱叫。按照OO技术的开发原则,我们首先会让鸭子实例的超类Duck实现这些方法,已进行代码的重复利用:

    DUCK
    quack()
    swim()
    display()
    //鸭子的其他方法
    其中,所有的鸭子均会叫,所以超类实现quack(),swim()方法。因为每种鸭子的外观不同,所以display()方法是抽象的,具体实现由其具体的子类实现。
    RedDuck
    //继承Duck超类
    display(){
    //我是红鸭子
    }
    DarkDuck
    //继承Duck超类
    display(){
    //我是黑鸭子
    }
    这样的设计到现在为止表现还是不错的,直到某一天,领导拍脑袋交代:鸭子要会飞才行。你觉得很简单:
    DUCK
    quack()
    swim()
    display()
    fly()
    //鸭子的其他方法
    但是你忽略了你们公司有些橡皮鸭继承了Duck超类,现在它们也飞了起来,真是太搞笑啦。你分分钟就想出了解决办法:让超类提供fly()的抽象方法,让子类去实现好啦,这样不会飞的鸭子什么都不做就好啦!
    RedDuck
    //继承Duck超类
    display(){
    //我是红鸭子
    }
    fly(){
    //我会飞
    }
    DarkDuck
    //继承Duck超类
    display(){
    //我是黑鸭子
    }
    fly(){
    //什么都不做
    }
    可是成千上万只鸭子中,只有几十只橡皮鸭而已,大多数鸭子都会飞,却无法进行代码的复用,继承的目的一方面不就是为了代码复用么?或者你想到了这样的方法:仍然超类实现fly()方法,而个别的鸭子对这个方法进行覆写,好吧,你赢了!等等,如果现在又要创造出一种新型鸭,叫声并不是呱呱叫,而是汪汪叫,怎么办呢,你当然可以继续覆盖超类中的quack()方法。好的,现在又要生产木鸭,既不会飞,也不会叫。覆盖,覆盖,你还能分清自己要覆盖的方法是什么吗?继承本身是为了简便,现在倒成了负担。这可咋整?

    看来继承并不能很好的解决问题了,那我们试试接口好啦。我把fly()和quark()方法从超类中分别提取出来做成接口,让具有其行为的鸭子才实现此接口。可是这样仍然没有解决代码无法复用的问题,造成了大量的代码重复。


    这样看来,并不是所有的鸭子都具有同样的行为,所以继承不是合适的解决方法;但是采用接口又无法实现代码复用。现在就来看看策略设计模式的灵通吧。

    策略模式的定义


    策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。


    设计原则一

    把会变化的部分取出并封装起来,以便日后可以轻易的改动或扩充此部分,而不影响其他不变部分。

    现在我们要把fly()和squack()方法提取出来,并且封装起来。

    设计原则二

    针对接口编程,而不是针对实现编程。

    刚才我们的做法是:行为来自超类的实现,或者行为来自子类的实现。实现,实现,瞧吧,我们被实现绑架啦。与之前不同的是,可变行为的实现不再由鸭子类实现,而是交由专门的实现类实现。


    真正编程接口的含义

    更确切点,我们说针对超类型编程,此处的超类型接口不只是interface,还包括abstract class,此处的关键是利用多态。也就是说,变量的定义应为超类型形式,即接口或抽象类,这样任何实现此接口或抽象类的子类均可赋值给此变量,声明类时无需理会真正的对象类型。


    封装行为的大局观

    1.定义鸭子超类,实现公用方法

    Duck
    //定义鸭子超类
    FlyBehavior flybehavior
    QuackBehavior quackbehavior
    swim()
    fly()
    squack()
    display()
    setFlybehavior()
    setQuackbehavior()
    2.封装fly接口
    interface fly
    fly()
    Fly1
    //实现Fly接口
    fly(){//实现fly}
    Fly2
    //实现Fly接口
    fly(){//什么都不做}
    3.封装quack接口
    interface Squack
    quack()
    Squack1
    //实现Squack接口
    quack(){//咕咕叫}
    Squack2
    //实现Squack接口
    quack(){//呱呱叫}

    setFlybehavior()和setQuackbehavior()方法可以动态的设定两实例对象,实时改变鸭子子类的行为,实现了代码的复用和可变与不变的分离。这就是策略模式的精髓所在。

  • 相关阅读:
    Codeforces758C
    Codeforces758B
    CodeForces758A
    数据库实习
    数据结构实习-迷宫(基于Qt实现)
    CodeForces757B
    CodeForces757A
    HDU3790
    数据结构实习
    Codeforces374B
  • 原文地址:https://www.cnblogs.com/torresliang/p/4315057.html
Copyright © 2020-2023  润新知