先对策略模式有一个总体认识。
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
结构:
下面通过鸭子模拟器的设计来具体介绍。
公司需要设计一套鸭子模拟器系统,该系统的第一次需求为:鸭子能够戏水;鸭子能够呱呱叫。根据该需求系统设计如下:
这个设计主要用了父类鸭子和子类绿头鸭、红头鸭,这样设计的目的是为了达到代码的复用。
过了一段时间,公司希望该系统能够满足新的需求:有些鸭子会飞。因此该系统需要进行修改,修改后的系统可能如下:
该系统在父类中加了“fly()”方法(在父类中加该方法是为了实现代码的复用)。这里就出现了两个问题:
(1)、所有的鸭子都会飞了。
(2)、所有鸭子的叫声都一样,都是“呱呱”叫。
注:这两个问题可以通过子类中方法覆盖来解除,但这样处理不是很好。鸭子的类别越多,这种处理的缺点就越明显。
其实这个系统的变化点是鸭子的叫声和鸭子的飞行能力,因此我们很容易想到把鸭子的叫声和鸭子的飞行能力做成接口,把这些变化的地方封装起来,这样上面的两个问题都可以解决,所以系统可能被修改为下面的样子:
MallardDuck和RedheadDuck既会飞又会叫,RubberDuck只会叫不会飞,DecoyDuck不会飞也不会叫。应该说这个系统没有问题了,从表面看这种设计完全符合需求,而且完全符合面向对象的理念,但是当鸭子的类别很多时,你会发现这种设计缺乏代码的复用,这两个独立出来的接口似乎没有任何意义,根本无法减轻工作量,还不如原来的设计呢。所以你可能会想到问题的关键是接口中的方法没有实现,那我们该怎么办呢?
我们的做法是把接口做成类,运用组合的方法来实现需求。考虑到“针对接口编程,而不是针对实现编程”的设计原则,我们的系统可能就会设计成如下的结构,这个结构就是应用了“策略”模式。