以一个有关鸭子的电子游戏“SimUDuck”开始,初始设计为
这时,有了一个新的需求,需要让鸭子可以飞
第一次设计:(在父类Duck上加一个fly方法,此时所有子类都继承该方法)
然而,经理在演示该项目时,用的是橡胶鸭子,并表示橡胶鸭子不应该会飞(忧伤的程序员。)
该怎么解决这个问题呢?(给一个父类增加了方法,可是部分子类不需要该方法,甚至是不能有该方法)
第二次设计:(增加Flyable接口和Quackable接口,让有需要的鸭实现该接口)
的确这样设计解决我们之前的问题,每个鸭子都有自己所需要的方法,可同时该方法造成了代码冗余,违背了DRY原则
该怎么解决这个问题呢?(每个子类都需要实现接口,导致各子类间代码重复冗余)
第三次设计:(对接口进行不同的实现,此时Duck类不在继承或者实现接口,而是在类中实例化一个对象,此时,Duck类与Fly和Quack之间将不存在继承关系,解决了第一次设计的问题,同时因为已经对Fly接口进行实现,Duck类不在需要自己实现Fly接口,解决了第二次设计的问题)
代码(Duck抽象类,定义接口类型):
同时,增加set方法(可动态改变)
在Duck的子类中,对接口进行实例化
总结:
1. 将应用中可能需要变化的地方独立出来,不要和那些不需要变化的代码混在一起 {
如例子中的fly方法,因为存在变化性,就不要和类似于display方法这样的固定刚需方法混在一起
}
2. 针对接口编程,而不是针对实现编程 {
如例子中,不是由Duck类来实现Fly接口,而是我们新建FlyXX类来实现Fly接口,这样,鸭子的行为作为独立类,而不是由Duck父类来具体实现(设计1),或者继承某个接口后由子类实现(设计2),这样鸭子的行为就不会被绑死在Duck类上
}
3. 多用组合,少用继承 {
在例子中,组合即是Duck类与Fly等行为类结合起来使用,使用组合建立系统能有很大的弹性,更可以在运行时动态改变行为
}
4. 上述例子的改写过程,用的便是策略模式 {
策略模式定义了一系列的算法(例子中的Fly和Quack行为都属于算法),分别封装起来,让他们之间可以互相替换,使算法的变化独立于使用算法的客户(例子中Duck类与Fly等行为类将不会因为继承关系互相影响)
}
当然,策略模式也有缺点:
1. 客户端需要知道所有策略类
2. 策略模式会生成很多策略类