设计模式 -- 策略模式

    设计模式,我对它的理解就是,解决问题的方法,模式本身的重要性自不必说,但是我认为模式之外的解决问题的方法才是我们真正需要掌握的,

                   其中,最基本的三点:封装变化,模块化,模块间的低耦合 

    以前也看过Head first 设计模式,但总有点雾里看花的感觉,总觉得不是那么的真切。不过一些思想已经印在脑子里了,这半年来体会良多,于是决定再把这本书看一遍,温故而知新。

    对于软件开发而言,一个很让人头疼的一个拦路猛虎就是“变”,可能是客户有了新的需求,可能是我们要使用新的技术,也可能是我们本领提高了,想要来重构原来的软件……

    设计模式很大程度上也是为了解决“变”的问题,当有变化产生的时候,如何使我们的代码改动最少,如何做到模块的独立性,使模块间的影响最小(也就是松耦合), 关于变化的一个设计原则是:

 

设计原则 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要发生变化的代码放在一起。

 

 我们来看一看,这个原则是怎么应用在鸭子问题上的:

1. 鸭子会 叫(quack),游泳(swim),...(未知的行为,会引起变化的部分

2. 有多种鸭子:绿头鸭(MallardDuck),红头鸭(RedheadDuck),模型鸭....(未知种类的鸭子,会引起变化的部分) 

3. 鸭子可能会有更多的行为,不同鸭子的行为也不同

 

如果这是一道分析设计题目,我很容易就会想到继承,分析如下:

我的方案1: 

    1. 将鸭子(Duck)类设计为抽象类,在其中实现我以为通用的行为,如swim,这样可以使得子类就可以重用父类的代码,如何做到代码重用也是一个问题呢

    2. 鸭子类的子类,包括MallardDuck啊,RedheadDuck啊什么的,在这些类中重写那些他们独有的行为。

 

 下面来看看这个方案的问题吧

 首先,继承有一个问题:父类中所作的任何修改都会反应到子类中,

         比如,我在父类中增加了一个fly方法,那么所有的子类都会继承这个方法,

         如果有的鸭子不会飞,我就要在子类中重写这个方法,从而父类的变化牵动了子类一块变化(而这正是我们想要解决的问题)

         可能你会说,这是需求不明确造成的,呃~,需求真的能明确么?

 其次,如果某几个子类的某种行为相同,这就会造成代码重复,当然了,你可能会采取某种方法来消除这种重复,例如,将这段重复的代码封装到一个函数中。

 再次,你能想象这样的设计如何实现运行时动态改变鸭子的行为么? 


怎样找出解决方法? 

     这个时候就是我们学以致用的时候了,根据设计原则,"找出应用中可能需要变化之处,把他们独立出来"。

设计原则 针对接口编程,而不是针对实现编程。

 

 这条设计原则比较抽象,不易理解,但是想让我们来看下我们的鸭子类,

 鸭子类中实现了quack(),swim()这些我们自以为通用的行为,这就造成鸭子超类依赖于具体的实现。

 而我们想要的是:鸭子类不需要关心实现的细节。 

 

 既然我们的标题是策略模式,那么就让我们看看策略模式,以及策略模式如何解决这个问题。

 

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

 

 这里所说的算法是一个泛泛的概念,它想表达的含义是将相同类型的行为视为一个算法族,如swim,quack等

  冒泡排序,希尔排序,快速排序,这可以被定义为一个算法族,

  同样的,对应于我们的鸭子,

  swim也可以被定义为一个算法族,蝶泳,狗爬式,等等, 

 以此类推,我们可以将swim, quack,fly这三种行为提取出来,封装为三个接口,简单的实现如下:

  1 // Fly行为接口

 2  class FlyBehavior{
 3  public:
 4      virtual  void fly() =  0;
 5      virtual ~FlyBehavior(){};
 6 };
 7 
 8  class Duck{
 9  public:
10      //  添加此方法以支持运行时动态修改 fly行为
11       void setFlyBehavior(shared_ptr<FlyBehavior> fb){
12         flyBehavior = fb
13     }
14 
15      //  我们的fly
16       void fly(){ 
17         flyBehavior->fly() ;
18     }
19 
20  private:
21      //  使用组合的方式
22      shared_ptr<FlyBehavior> flyBehavior;
23 };

 

 上边的代码只是简单地实现了鸭子类 和 FlyBehavior ,不过雏形确已初具,

 Duck的子类只需要使用正确的行为类就可以了。

 而父类接口的变化,对子类的影响也很小;

 如果代码中的鸭子类增加了新的行为,如swim(),那么,子类只需要调用setSwimBehavior()设置正确的Swim行为就可以了,而子类的实现不必发生变化

 更好地方式是,我们采用工厂方法,将创建鸭子的行为封装在工厂方法中

 

 

你可能感兴趣的:(设计模式)