策略模式——从鸭子入手

一个鸭子类,子类有绿头鸭和红头鸭。



      每个鸭子都会叫,也会游泳,所以由超类来处理这些共同的东西。而display()方法是用来显示,更加直观的体现各部分的关系。

     当涉及维护时,为了复用而使用继承,问题往往更大。

     如果我们在Duck类中加一个fly()飞的方法,结果会怎么样?


      由于考虑不周,在Duck类中增加了fly(),这样ToyDuck玩具鸭子也继承了这个方法。可是事实上玩具鸭子是飞不起来的,那怎么办?类似的问题是,玩具鸭子只会吱吱地响,而不会向红头鸭那样呱呱的叫。

      这时,我们就要用“覆盖”了,将ToyDuck玩具鸭中的fly()方法覆盖掉,变成什么也不做,类似的,将quack()方法覆盖为吱吱叫。



      到这里,好像勉强是可以完成任务了。但当一个新的鸭子子类出现的话,我们都要考虑它是不是能飞,是不是能叫,是怎样飞的,怎样叫的。可见,这样的实现方法并不能一劳永逸。

      这时,我们可以考虑将一些容易或可能经常发生变化的一些方法,如fly,quack,从Duck抽象类中取出来,放到一个接口中,然后让会飞的绿头鸭、红头鸭去实现这个接口,而玩具鸭子就不去实现它了。


      引入接口之后,事情就方便多了,可这样一来,各个子类的代码就没办法复用了。

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

     为了分开变化的和不变化的部分,需要建立两组类,一个是与fly相关的,一个是quack相关的,每组类各自实现各自的动作。我们将这两个行为从Duck类中分开,建立一组新类。

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

     鸭子的子类将使用接口FlyBehavior和QuackBehavior所表示的行为,事实上的实现不会被绑死在鸭子的子类中。比如,玩具鸭子不能飞,这样的设计就可以在运行时动态的改变它的飞行行为。


整合之后的全图就变成了下面的样子:


由于精力有限,Duck中的部分地方没有说明。比如Duck类加了中两个实例变量 fly 和 quack,但并不影响理解。

对比之前商场打折的例子:


      通过这两个例子,相信你会对策略模式有了更深入的理解。即使同样是理解了,总结与不总结收获差别蛮大的。

      顺着书上的思路走,虽然挺麻烦的,也走了弯路,但正是这样,才能更深刻的理解那些原则、经验。剩下要做的就是结合代码再重新梳理一下思路了。


posted @ 2014-09-22 18:00  Sherry&Yang  阅读(376)  评论(0编辑  收藏  举报