The Strategy Pattern (策略模式)

Joe所在的电脑游戏公司研发了一款游戏软件,模拟池塘中各种鸭子嬉戏(游动并且鸣叫)的场景。软件很受欢迎。

设计一个Duck超 类,各种鸭子都继承这个超类。所有的鸭子都会鸣叫和游水,所以Duck超类实现quack()和swim()方法。由于不同种类的鸭子样子不同,所以 Duck中的display()方法设计为抽象方法。不同的鸭子子类通过实现display方法显示自己的样子。

游戏上市后的次年,竞争越来越激烈。在外出度假一周后,公司高管们决定要对游戏作重大创新,在下周的股东大会上,他们要让股东们“印象深刻”。

高管们觉得,如果鸭子能够飞起来,则能击败同类游戏的竞争者。Joe的上司告诉高管们,Joe可以在一周内搞定,因为他是一个 OO Programmer…



但 是,一周后Joe的经理从股东大会上打来电话…Joe,我在股东大会上,刚刚演示了游戏,他们看到屏幕上有许多橡皮玩具鸭子在飞来飞去,你是不是故意搞 笑?!偶的错,偶忘了不是所有的鸭子都会飞!在Duck中增加一个fly()方法,则它的所有子类就都有飞的能力了。没想到,一个局部的修改产生了非局部 的副作用。
在子类RubberDuck中重写fly()方法,让它什么都不做。还有,橡皮鸭也不会嘎嘎叫,只会吱吱叫,这样quack()方法也要改写。但是,如果考虑再增加打猎用的仿真鸭该怎么办呢?它既不会叫也不会飞,这样又得改写方法了。烦!看来,继承这东西有时也挺烦人的!
公司高层决定每半年就要更新该产品,更新的方式他们还没有想好。。。。。。。。。。。。。。。
必须要有一种清晰的方法,让一部分鸭子(而不是全部)能够飞行和鸣叫。把fly()从Duck中分离出来,设计一个接口Flyable,该接口有一个fly()方法,会飞的鸭子就实现该接口。对quack()也依此处理。


Joe的第二个方案解决了部分问题(不会有会飞的橡皮鸭了),但也完全破坏了代码的重用性(每一种会飞的鸭子都必须实现fly()方法,如果要修改飞行行为,则必须修改每种鸭子的fly()代码,设想有几十种会飞的鸭子)。这从另一个方面增加了维护的难度。


正确的解决方案

现在让我们将鸭子的行为从Duck类中分离出来!
我们已经知道,fly()和quack()是Duck类中不同的ducks的变化部分。我们将这些行为从Duck类中分离出来,对于每一个方法,创建一个类的集合来表示相应的行为。例如:对于fly(),我们建立一个类的集合,分别实现翱翔,俯冲,起飞等。

怎么设计实现鸭子飞行和鸣叫行为的类集合?
首 先,我们需要灵活性。在此之前,正是由于不灵活给我们带来了麻烦。我们希望能够将行为指定给鸭子的某个实例。例如,我们可能希望生成一个野鸭实例,并以某 种飞行行为(例如:翱翔)对它初始化,在这之后,我们就会想能不能动态的改变这只野鸭的行为呢?换句话说,我们应该在Duck类中包含一个设置行为的方 法,使得我们能够在运行时改变野鸭的行为(如:由翱翔变为俯冲)
引入接口
对每类行为,我们用一个接口(interface)来表示。例如:用接口FlyBehavior来表示飞行行为,用接口QuackBehavior来表示鸣叫行为。每一个具体的行为类,是这些接口的一个实现(如:翱翔Hover,俯冲Dive,不飞)。
这样做之后,就不是由Duck类来实现飞行和鸣叫接口了,取而代之的是,我们设置了一组类,他们的任务就是表示某个行为,这些行为类将用来实现上面的接口。

新设计方法与以前的方法的差异
这 种做法与我们以前的做法不同,以前我们或者是用Duck超类,或者是用Duck的子类本身来具体实现(implements)一个接口。后两种做法都使我 们依赖于一个实现,我们被使用这种特定的实现捆住了手脚,要改变鸭子的行为时除了对Duck类或其子类进行修改,增加代码外,别无它法。
在我们新的设计方案中,Duck的子类将使用由接口(FlyBehavior或QuackBehavior)表示的行为,而接口由行为类具体实现,这样,行为的具体实现就不会被固化在Duck的子类中了。

代码列表

1.Duck.java
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } public void setFlyBehavior (FlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb) { quackBehavior = qb; } abstract void display(); public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public void swim() { System.out.println("All ducks float, even decoys!"); } } 2.FlyBehavior.java
public interface FlyBehavior { public void fly(); }
3.QuackBehavior.java
public interface QuackBehavior { public void quack(); } 4.FlyWithWings.java
public class FlyWithWings implements FlyBehavior { public void fly() { System.out.println("I'm flying!!"); } }
5.FlyNoWay.java
public class FlyNoWay implements FlyBehavior { public void fly() { System.out.println("I can't fly"); } }
6.FlyRocketPowered.java public class FlyRocketPowered implements FlyBehavior { public void fly() { System.out.println("I'm flying with a rocket"); } }
7.MuteQuack.java public class MuteQuack implements QuackBehavior { public void quack() { System.out.println("<< Silence >>"); } } 8.FakeQuack.java public class FakeQuack implements QuackBehavior { public void quack() { System.out.println("Qwak"); } } 9.MallardDuck.java public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck"); } } 10.ModelDuck.java public class ModelDuck extends Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display() { System.out.println("I'm a model duck"); } } 11.MiniDuckSimulator.java public class MiniDuckSimulator{ public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly(); Duck model = new ModelDuck(); model.performFly(); model.setFlyBehavior(new FlyRocketPowered()); model.performFly(); } }
The End--------------------!


你可能感兴趣的:(The Strategy Pattern (策略模式))