在开始看设计模式之前我们先复习一下oo的设计基础和设计原理
图1
原文章链接:点击打开链接
设计原理(并不是全部,只是这个模式所用到的):
图二
图三
图四
策略模式的定义:定义了算法族,分别封装起来,让他们之间可以相互替换,这个模式让算法的定义独立于使用算法的客人
看了这个定义你也许对策略模式是一头雾水,别急,接下来我们用一个实际项目来理解
项目名称:模拟鸭子
项目描述:这是一个模拟鸭子的游戏,游戏中会出现各种各样的鸭子,有绿色羽毛游水的真鸭,有会游水的黄色橡皮鸭,还有会飞正在呱呱叫的鸭子......
项目分析:首先这个项目的对象很清晰,就是鸭子,但是我们需要给鸭子赋予不同的属性,在这些属性中有些是不变的(每个鸭子对象都会有的),比如:鸭子的外观,还有一些是变化的(不是所有的鸭子都会的),比如:鸭子的飞行,叫声
项目设计
注:extends
implement
一.(未使用策略模式,单纯使用继承):
图六
出现的问题:1.代码在多个子类中重复(不同的鸭子子类需要去覆盖父类中方法)
2.运行时的行为不容易改变(如要修改其中一个鸭子的行为就必须要修改覆盖父类方法的代码)
3.很难知道其中某个鸭子的所有行为
4.改变会牵一发而动全身,造成其他鸭子不想要的改变
二.(使用了策略模式):
图七
上面设计中出现的问题,我们根据文章开头提到的设计原理做一步步的改造
首先根据原则一,我们要把鸭子中会变化的属性单独提出来,也就是上述分析中的飞行动作和叫的动作,建Flyable和Quackavle接口有需要这些属性的鸭子就implement接口
图八 出现的问题:因为接口不具备具体的实现,以至于我们在鸭子实例中还是要具体的实现,还是存在上面的问题
根据原则二:在上面一个解决方法中,虽然每个具体的鸭子类implement了接口,但是在这些鸭子类中还是要去具体去实现接口,这就是针对实现编程,而我们的目的在于针对接口编程。
原则二解释:声明一个接口类型的变量,但是new(实现)的时候却是一个实现类(此类implement了这个接口,运用了多态)
在这个模型中我们创建了不同的实现类(FlyWithWings,FlyNoWay)去implement Fly这个接口,在这些类中具体的写出飞的方法,需要飞行动作的类就可以声明Fly接口的变量,然后这个变量再new具体的实现类。(叫的动作实现的方法也是一样的)
图九
据原则三,使用组合把这个项目整合,在Duck类中声明飞的变量flyBehavior(implement Fly),在飞的方法中去调用接口中的方法flyBehavior.fly()(fly()在Fly接口中定义了),这样一来Duck类中就可以完全不需要知道具体的飞的方法,它只需调用接口的方法就可以。(叫也是同样的做法)
图十
然后不同的鸭子类去extends这个Duck类,引用Duck类中的flyBehavior变量去new一个FlyWithWings类,这样一来这个鸭子就有了翅膀飞行的属性了。这些具体的鸭子是通过组合形成的,虽然用到了继承但是总体来说鸭子的其中飞行动作是一个类,这个类和其他的属性组合成了一个具体的鸭子。
好了,到这里这个项目的整个设计已大概完成。我们这篇文章的重点策略模式不知你是否在心中已有了一个概念,最后我们再重新梳理一下这个策略。
首先这个策略的重点在于定义算法族并进行封装,回顾上述的项目,我们把鸭子的行为说成是“一组行为”也就是策略上的“一族算法”,鸭子的不同属性(不同的叫和飞)代表了算法,然后我们封装了这些算法。且这些封装的算法独立于客户,客户还可以动态的互相替换(图七)
本文到这里已全部结束,恭喜你!又学到了一点新的内容!
注:本文中所有图片全都来自《Head First设计模式》一书中的截图
参考:《Head First设计模式》