设计模式,我对它的理解就是,解决问题的方法,模式本身的重要性自不必说,但是我认为模式之外的解决问题的方法才是我们真正需要掌握的,
其中,最基本的三点:封装变化,模块化,模块间的低耦合
以前也看过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行为接口
上边的代码只是简单地实现了鸭子类 和 FlyBehavior ,不过雏形确已初具,
Duck的子类只需要使用正确的行为类就可以了。
而父类接口的变化,对子类的影响也很小;
如果代码中的鸭子类增加了新的行为,如swim(),那么,子类只需要调用setSwimBehavior()设置正确的Swim行为就可以了,而子类的实现不必发生变化
更好地方式是,我们采用工厂方法,将创建鸭子的行为封装在工厂方法中。