zoukankan      html  css  js  c++  java
  • 浅入浅出设计模式策略模式篇

    浅入浅出设计模式

     

    简介                                                                                  

    GoF(“四人帮”Gang of Four,指Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides四人)的《设计模式》(1995年出版)是第一次将设计模式提升到理论高度,并将之规范化。本书提出了23种基本设计模式,自此,在可复用面向对象软件的发展过程中,新的大量的设计模式不断出现。

    1.从前有一群鸭子                                                               

    在遥远的丹麦生活着一群快乐的鸭子,它们会唱歌(quack),跳舞(swim)还会表现自己(display)。我们来把这群鸭子设计成一个类。UML图如下所示

    就像我们看到的,每只鸭子都会同样的行为。

    2.有鸭自远方来                                                                  

    后来的一天,从非洲来了一群“南非鸭”,它们和丹麦鸭一样会唱歌跳舞,不过表现自己就和丹麦鸭的表现不同了。

    那这里我们就来用抽象类的方式来解决这个问题,如下图所示(抽象用斜体表示)

    这样,我们通过一个抽象类Duck来实现quack和swim方法的复用,而不同的地方display由继承的子类分别实现。

    要点1:找出应用中可能变化之处,把它们独立出来,不要和那些不需要变化的代码混合在一起。

     

    3.每只鸭子上辈子都是折翼的天使                                         

    那是一个电闪雷鸣的日子,鸭老大给小鸭们讲了它们祖先天鹅翱翔于蓝天的故事。原来,它们上辈子都是折翼的天使……

    于是,这群鸭子展开翅膀~~  灰了起来 - -||

    到了这里,鸭子们需要一个飞(fly)的方法,既然大家都会飞,就加到父类Duck里吧。

    但是,有的鸭子(玩具鸭,姑且算鸭子吧)不会飞啊~~  那该怎么办呢?我们的设计是不是出现了错误?

    嗯~ 我们先覆盖父类中的方法来实现我们的需求吧。

    OK,我们实现了需求

    要点2:为了"复用"(reuse)目的而使用继承,貌似不是很好

    仔细思考:
    
    1、我们是不是把这个问题解决了?
    
    2、如果又来了个A鸭子(不会叫,不会有用,不会飞);或者是B鸭(会汪汪叫,会游泳,不会飞)等等,我们该怎么办?
    
    3、利用继承来提供Duck的行为,这会导致下列哪些缺点?
     a.代码在多个子类中重复
     b.运行时的行为不容易改变
     c.我们不能让鸭子跳舞
     d.很难知道所有鸭子的全部行为
     e.鸭子不恩那个同时又飞又叫
     f.会造成其他鸭子不想要的改变
    
    

    4.你是否想到了"接口"                                                        

    看起来不错的样子~

    如果子鸭子类特别多,问题就出来了,那岂不是每种鸭子都各自实现?无法实现代码复用的目的?

    1、现在我们知道使用继承并不能很好的解决问题,因为鸭子的行为在子类里不断的改变,并且让所有的子类都有这些行为是不恰当的。

    2、Flyable和Quackable接口一开始似乎不错,解决了问题(只有会飞的鸭子才继承Flyable),但是接口不具有实现代码,所以继承接口无法达到代码的复用。

    要点3:多用组合,少用继承

    5.重新设计鸭子                                                              

    Ⅰ.分开变化和不会变化的部分

    (本图截取自深入浅出设计模式

    Ⅱ.针对接口编程 (题外话)

    我们利用接口代表每个行为,比方说IFlyBehavior和IQuackBehaviour,而行为的每个实现都将实现其中的一个接口。

    这种方法和以往不同的地方在于,以前的做法是:行为来自Duck父类的具体实现,或者是继承某个接口并由某个接口来自行实现而来。这两种做法都是依赖于“实现”, 我们被实现绑住,没办 法更改行为(除非写更 多的代码)

    举例说明:
    
    "针对实现编程"
    Dog d=new Dog();
    d.bark();
    
    "针对接口/超类型编程"
    Animal animal=new Dog();
    animal.bark();
    
    更好的是,子类实例化的动作不再需要在代码中硬编码,例如
    new Dog();而是"在运行时才指定具体实现的对象"
    a=getAnimal();
    a.makeSound();
    

    Ⅲ.实现鸭子的行为

    Ⅳ. 整合鸭子的行为

    注意,上图中的Duck的两个成员是接口类型,即我们上面提到的IFlyBehavior 和IQuackBehavior 接口类型

     

          

    别忘记,因为yellowduck继承了duck的,所以具有flyBehavior和quackBehavior实例变量

     

    Ⅴ. 测试代码

    输入并编译测试类

     

    public class MiniDuck()
    {
    	public static void main(string[] args)
    	{
    		Duck mini=new YellowDuck();
    		mini.performFly();
    		mini.performQuack();
    	}
    }
    
    


    ⑤运行代码

     

    6.总结                                                              

    上图是整个重新设计后的类图

    我们这里描述事情的方式也少有改变。不再把鸭子的行为说成是“一组行为”。我们开始把行为想成是“一组算法”。

    而上图就是GoF的设计模式中的策略模式

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

     

     

     

     

     

     

  • 相关阅读:
    内存
    TCP/IP
    安装
    linux常用命令
    linux文本处理三剑客之 grep
    tail命令:显示文件结尾的内容
    less命令:查看文件内容
    head命令:显示文件开头内容
    改进Zhang Suen细化算法的C#实现
    【转】在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
  • 原文地址:https://www.cnblogs.com/TivonStone/p/1825147.html
Copyright © 2011-2022 走看看