首页 > 代码库 > 策略模式

策略模式

定义

策略模式定义了算法族,分别封装起来。让它们之间能够相互替换。此模式让算法的变化独立于使用算法的客户。

类图

技术分享

设计原则

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

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

      3.多用组合。少用继承。

   

举例分析

    设计一个模拟鸭子游戏,游戏中会出现各种(木头鸭、橡皮鸭等等)鸭子。一边游泳(swim)。一边叫(quack)。系统类图例如以下:

技术分享

去年。公司的竞争压力加剧,此类游戏非常多。公司开会决定要对游戏进行升级,要求有些鸭子会飞。程序要Joe是这样设计的,例如以下:

技术分享

       程序完毕后,当在股东会议上演示的时候,有非常多“橡皮鸭”竟然会飞。(方法覆盖能够解决此问题,假设有100个不同类型的鸭子。就得重写100次。

在超类Duck中加上fly()方法。就会导致全部的子类都具备fly()。连那些不该具备fly()的子类也无法免除。

Joe认识到继承可能不是答案,于是Joe有设计了一种方法。例如以下:

技术分享

技术分享

        Joe的上司看了这个设计后,这真是一个超笨的注意,你没有发现这么一来反复的代码会变非常多吗?(全部须要quack()fly()方法的鸭子都去反复实现这两个方法)假设你觉得覆盖几个方法就算是差劲。那么对于100个Duck的子类都要改动一下飞行(fly())的行为。你又怎么说。

       我们知道。并非全部的鸭子都会飞、会叫。所以继承不是正确的方法。可是尽管上面的使用Flyable接口的方法,能够解决部分问题(不再有会飞的橡皮鸭子),可是这个解决方式却彻底破坏了重用,它带来了还有一个维护的噩梦!

甚至,在会飞的鸭子中。飞行的动作可能还有多种变化......。

     呵呵,假设是你你会怎么办?

      细致思考一下,由于鸭子的行为会在子类里不断的改变,Flyable接口攻克了仅仅有会飞的鸭子才实现Flyable接口。可是这样的方法无法达到代码复用。这就须要我们的第一个设计原则“分开变化和不会变化的部分”。

      我们知道Duck类内的fly()和quack()会随着鸭子的不同而改变。

我们须要做的就是把fly()quack()行为从Duck基类里隔离出来。我们希望一切能有弹性,可以指定行为到鸭子实类。比如:我们可能想要实例化一个新的野鸭实例,而且给它初始化一个特殊类型的飞行行为(飞行能力比較强)。换句话说,我们应该在鸭子类中包括设定行为的方法,这样就行在“执行时”动态的“改变”野鸭子的飞行行为。有了这种目标。看看第二条设计原则“针对接口编程。而不是针对实现编程”。

       ”针对接口编程“。关键就在于多态。利用多态,程序能够针对超类编程。运行时会依据实际情况运行到真正的行为,不会被绑死在超类的行为上。

       依据面向接口编程的设计原则,我们应该用接口来隔离鸭子问题中变化的部分,也就是鸭子的不稳定的行为(fly()quack())。我们要用一个FlyBehavior接口表示鸭子的飞行行为,QuackBehavior接口表示鸭子的叫声行为。如以下的类图:

技术分享

          这种设计。能够让飞行和呱呱叫的行为被其它的对象复用。由于这些行为已经于鸭子类无关了。

二我们能够新增一些行为。不会影响到既有的行为类,也不会影响“使用”到飞行行为类的鸭子类。

        说的有点多。接下来来实现这样的设计:

         1.在Duck类中增加两个实例变量,各自是“FlyBehavior”与“QuackBehavior”。每一个鸭子对象都将会动态的设置这些变量,以在执行时引用正确的行为类型。

     2.我们还要把fly()quack()方法从Duck类里移除,由于我们已经把这些行为到FlyBehaviorQuackBehavior接口里了。

     3.在鸭子的超类中设定SetQuackBehavior()SetFlyBehavior()那么就能够在执行时动态改变鸭子的行为了。

具体设计类图

技术分享

 源代码 

 http://download.csdn.net/detail/allen_gang/7492871

參考Head First Design Patterns

策略模式