策略模式--《HeadFirst设计模式》

良好的OO设计必须具备可复用、可扩充、可维护三个特性

模式可以让我们建造出具有良好OO设计质量的系统

Joe是一名OO程序员,他为一家开发模拟鸭子池塘游戏的公司工作,该公司的主要产品是一种可以模拟展示多种会游泳和呷呷叫的鸭子的游戏。这个游戏是使用标准的面向对象技术开发的,系统里所有鸭子都继承于Duck基类,系统的核心实现类:

一:使用继承

Joe 设计了一个鸭子类,作为所有鸭子的超类。鸭子会呱呱叫(Quack)、也会游泳(Swim),那么由超类负责处理这部分的实现, 还有一个负责展示鸭子的外貌的 display 方法,它是抽象的,由各个具体的鸭子描述自己的外貌。代码如下:

鸭子类

增加需求:商场如战场,不进则退。Joe的公司最近的日子不好过,盗版泛滥,再加上竞争对手的围追堵劫,已经拖欠好几个月工资了。因此,公司高层在一次集体“腐败”后,决定一定要给系统增加一些超玄的功能,以彻底击垮竞争对手。经过董事会讨论,最终觉得如果能让鸭子飞起来,那么一定可以给对手致命一击。于是Joe的上司对董事们拍着胸脯说:“这没有问题,Joe是一个OO程序员,这对他来说太简单了!我们保证一周内结束战斗。”

接到任务的Joe丝毫不敢怠慢,研究了上级的指示以后,发现只要在Duck里增加一个fly()方法就可以搞定了,这样所有继承Duck的鸭子就都拥有了会飞的能力,哈!这回奖金有盼头啦!改进后的系统如下:

增加fly的鸭子类

实际开发中经常见有人这样做——子类如果不需要父类的某个方法,就强行覆盖。

问题:利用继承来提供 Duck 的行为,会导致下列的一些问题:

1、代码在多个子类中无意义的重复——比如玩具鸭子不需要飞翔,但是还得必须显示的覆盖这部分的代码。

2、运行时的行为不容易改变——代码都继承到了子类,等于代码是被写死了。

3、无法灵活的扩展——比如,新加入了木头的玩具鸭子,木头的鸭子不会呱呱叫,也不会飞翔,这就仍然需要很笨重的给木头鸭子覆盖呱呱叫+飞翔的方法,让其什么都不做。

4、很难知道所有鸭子全部真正的行为,无法容易的得到,某个鸭子类,到底需要实现的行为是什么。

5、牵一发动全身,造成其他鸭子不想要的改变——比如又要给鸭子增加跳舞的行为,那么所有的不需要跳舞的鸭子,也都要去修改……

那么使用接口怎么样?我可以把fly()方法放在接口里,只有那些会飞的鸭子才需要实现这个接口,最好把quack()方法也拿出来放到一个接口里,因为有些鸭子是不会叫的。就像下面这样:

二:使用继承+接口

使用继承+接口实现

虽然使用 Flyable  接口可以解决第一版继承带来的问题,但是却产生了代码无法复用的新问题。因为 Java 的接口在 1.8 之前,不能具有实现代码,所以除非你能肯定所有使用这个系统的人都是使用的 JDK 8及其以后的版本,否则继承接口无法 100% 确保达到代码的复用目的。

这就意味着:无论何时你需要修改某个行为,你必须得往下追踪,并在每一个定义此行为的类中修改它,一不小心,可能会造成新的错误。幸运的是,有一些设计原则,恰好适用于此状况。

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

策略模式UML图

设计原则:找出应用中变化之处,把它们独立,不要和那些不需要变化的代码混在一起

代码实现如下:

变化的行为
抽象鸭子类
具体鸭子类
测试类

总结:

OO基础:

封装、继承、多态、抽象

OO原则:

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程


策略模式具体代码实现

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容