策略模式
目录
一、从简单的模拟鸭子应用开始
Joe上班的公司做了一套模拟鸭子的游戏:SimUDuck。游戏中的各种鸭子一边游泳戏水,一边呱呱叫。此系统内部设计使用了标准的OO技术,设计了一个鸭子超累,并且让各种鸭子继承此超类。
public abstract class Duck { //抽象类
public Duck() {
}
public void Quack() {
System.out.println("~~gaga~~");
}
public abstract void display(); //抽象方法,每个子类都必须实现该方法
public void swim() {
System.out.println("~~im swim~~");
}
public void Fly() { //添加一个fly()方法
System.out.println("~~im fly~~");
}
public class RedHeadDuck extends Duck {
@Override
public void display() {
System.out.println("**RedHead**");
}
此时项目中需要添加新的功能,比说要程序中需要有会飞的鸭子,此时Joe在Duck类上添加了fly方法,这种方法有个弊端,所有的子类都会包含有fly方法,并非所有的duck类的子类都会飞。
Joe想到一个方法:用覆盖的方式把不会飞的子类中fly方法覆盖掉
public class GreenHeadDuck extends Duck {
//不会飞的鸭子
@Override
public void display() {
System.out.println("**GreenHead**");
}
public void Fly() { //覆盖
System.out.println("~~no fly~~");
}
}
用继承的方式来提供Duck的行为,会导致以下缺点:
1.代码会在多个子类中重复
2.运行时的行为不容易改变
3.无法得知所有鸭子的全部行为,并且鸭子不能够同时飞又叫
4.改变Duck类代码,会影响其他鸭子一起发生改变
二、改进版的鸭子应用
Joe把fly方法抽取出来,放进一个flyable接口中,这样一来,只有会飞的鸭子才实现此接口。同样的他也可以设计一个Quackable接口,并不是所有的鸭子都会叫。
这样子的方法同样也产生了一个问题,就是代码不能重用,每个子类都必须实现接口,如果有48个会飞的鸭子,那么就要实现48个飞的接口。
三、采用策略模式改进后的鸭子应用
3.1 策略模式中包含的设计原则
a.找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变的代码混在一起。把会变化的部分抽取出来并且封装起来,一边以后可以轻易地扩充此部分,而不影响不需要变化的部分。
b.针对接口编程,而不是针对实现编程
c.多用组合,少用继承
3.2 具体的方法
步骤一:为了分开【变化与不变化】的部分,建立了两组类,分别是fly相关,quack相关,每一组类将实现各自的动作。
步骤二:如何设计鸭子的行为(采用设计原则b)
利用接口代表每个行为,比如:FlyBehavior与QuackBehavior,而行为的每个实现都必须实现这些接口之一。所以鸭子不会负责实现Flying和Quacking接口,而是其他类专门实现FlyBeahavir和QuackBehavior接口,这就是行为类。由行为类实现行为接口而不是通过duck类实现行为接口。
这种做法不同于以往的做法,以往的做法是:行为继承Duck超类的具体实现而来,或者是继承某个接口并由子类自行实现。这些方法都依赖于实现。
问题:为什么不把FlyBehavior设计成抽象超类,而是接口
针对接口编程的真正意思是针对超类型编程,针对接口编程关键在于多态。利用多态,程序可以针对超类型编程,执行的时候会根据实际状况得到真正的行为,不会被绑死在超类型的行为上。超类型通常是一个抽象类或者一个接口。例子如下:
步骤三:实现鸭子行为
这样设计的好处:可以让飞行和呱呱叫的动作被其他对象复用,这些行为已经和鸭子类无关了。如果我们需要新增一些行为,不会影响到已有的行为类,而不会影响到使用飞行行为的鸭子类。
步骤四:整个鸭子的行为
具体代码如下:
Duck类:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.FlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.QuackBehavior;
public abstract class Duck {
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {
}
public void Fly() {
mFlyBehavior.fly();
}
public void Quack() {
mQuackBehavior.quack();
}
public abstract void display();
public void SetQuackBehavoir(QuackBehavior qb) { //动态的设定行为
mQuackBehavior = qb;
}
public void SetFlyBehavoir(FlyBehavior fb) { //动态的设定行为
mFlyBehavior = fb;
}
public void swim() {
System.out.println("~~im swim~~");
}
}
GreenHeadDuck类:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.GoodFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.GaGaQuackBehavior;
public class GreenHeadDuck extends Duck {
public GreenHeadDuck() {
mFlyBehavior = new GoodFlyBehavior();
mQuackBehavior = new GaGaQuackBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("**GreenHead**");
}
}
RedHeadDuck类:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.BadFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.GeGeQuackBehavior;
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
mFlyBehavior = new BadFlyBehavior();
mQuackBehavior = new GeGeQuackBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("**RedHead**");
}
}
飞行行为类:
package com.java.hexter.stimulateduck.flybehavior;
public interface FlyBehavior {
void fly();
}
package com.java.hexter.stimulateduck.flybehavior;
public class BadFlyBehavior implements FlyBehavior
{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("--BadFly--");
}
}
package com.java.hexter.stimulateduck.flybehavior;
public class GoodFlyBehavior implements FlyBehavior
{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("--GoodFly--");
}
}
package com.java.hexter.stimulateduck.flybehavior;
public class NoFlyBehavior implements FlyBehavior
{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("--NoFly--");
}
}
呱呱叫行为类:
package com.java.hexter.stimulateduck.quackbehavior;
public interface QuackBehavior {
void quack();
};
package com.java.hexter.stimulateduck.quackbehavior;
public class NoQuackBehavior implements QuackBehavior
{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("__NoQuack__");
}
}
package com.java.hexter.stimulateduck.quackbehavior;
public class GeGeQuackBehavior implements QuackBehavior
{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("__GeGe__");
}
}
package com.java.hexter.stimulateduck.quackbehavior;
public class GaGaQuackBehavior implements QuackBehavior
{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("__GaGa__");
}
}
测试代码:
package com.java.hexter.stimulateduck;
import com.java.hexter.stimulateduck.duck.Duck;
import com.java.hexter.stimulateduck.duck.GreenHeadDuck;
import com.java.hexter.stimulateduck.duck.RedHeadDuck;
import com.java.hexter.stimulateduck.flybehavior.NoFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.NoQuackBehavior;
public class StimulateDuck {
public static void main(String[] args) {
Duck mGreenHeadDuck = new GreenHeadDuck();
Duck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.Fly();
mGreenHeadDuck.Quack();
mGreenHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.Fly();
mRedHeadDuck.Quack();
mRedHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.SetFlyBehavoir(new NoFlyBehavior()); //动态修改行为
mRedHeadDuck.Fly();
mRedHeadDuck.SetQuackBehavoir(new NoQuackBehavior()); //动态修改行为
mRedHeadDuck.Quack();
}
}
四、总结
本案例采用的是策略模式,该模式覆盖三个设计原则,分别是面向接口编程、多用组合少用继承和将程序中可变与不可变的部分分开,其中多用组合少用继承是一种十分重要的技巧,案例中每一鸭子都有一个FlyBehavior和一个QuackBehavior,让鸭子将飞行和呱呱叫委托给他们代为处理。鸭子的行为不是继承而来的,而是采用适当的行为对象组合而来。