策略模式Strategt Pattern定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
说白了,就是在主函数新建一个类之后,调用相同的方法,得到的实现的结果是不同的,即使这些类是继承同一个抽象。
具体直接看一道2010年上半年的软件设计师的软考题来说明这个问题:
某软件公司先欲开发一款飞机飞行模拟系统,该系统主要模拟不同种类飞机的飞行特征与起飞特征,需要模拟的飞机种类机器特征如下所示:
直升机Helicopter:垂直起飞VerticalTakeOff、亚音速飞行SubSonicFly
客机AirPlan:长距离飞行LongDistanceTakeOff、亚音速飞行SubSonicFly
歼击机Fighter:长距离飞行LongDistanceTakeOff、超音速飞行SuperSonicFly
鹞式战斗机Harrier:垂直起飞VerticalTakeOff、超音速飞行SuperSonicFly
为支持将来模拟更多种类的飞机,采用策略设计模式Strategt Pattern,设计如下类图:
图6-1中,AirCraft为抽象类,描述了抽象的飞机,而类Helicopter、AirPlane、Fighter、Harrier分别描述具体的飞机种类,方法fly()和takeOff()分别表示不同飞机都具有飞行特征和起飞特征:类FlyBehavior与TakeOffBehavior为抽象类,分别用于表示抽象的飞机行为与起飞行为,类SubSonicFly与SuperSonicFly分别描述亚音速废弃和超音速起飞的行为,类VerticalTakeOff与LongDistanceTakeOff分别描述垂直起飞与长距离起飞的行为。
在写代码解答此题之前,我们先来看一下这个类图,也就是所谓的UML,AirCraft依赖于FlyBehavior与TakeOffBehavior,注定会在自己的类成员有这两个对象所对应的实体。之后类SubSonicFly与SuperSonicFly继承于FlyBehavior,VerticalTakeOff与LongDistanceTakeOff继承于TakeOffBehavior,Helicopter、AirPlane、Fighter、Harrier继承于AirCraft。子类注定是父类接口的实现。在FlyBehavior、TakeOffBehavior、AirCraft中,+表示该类存在的方法,-号表示该类存在的类成员,因此顺利成章地能够得到如下的代码:
//一、飞行方式
//1.接口
interface FlyBehavior {
public void fly();
};
//2.实现
class SubSonicFly implements FlyBehavior {
public void fly() {
System.out.println("亚音速飞行!");
}
};
class SuperSonicFly implements FlyBehavior {
public void fly() {
System.out.println("超音速飞行!");
}
};
//二、起飞方式
//1.接口
interface TakeOffBehavior {
public void takeOff();
};
//2.实现
class VerticalTakeOff implements TakeOffBehavior {
public void takeOff() {
System.out.println("垂直起飞!");
}
};
class LongDistanceTakeOff implements TakeOffBehavior {
public void takeOff() {
System.out.println("长距离起飞!");
}
};
//三、飞机
//1.飞机的抽象
abstract class AirCraft {
protected FlyBehavior flyBehavior;
protected TakeOffBehavior takeOffBehavior;
public void fly() {
flyBehavior.fly();
}
public void takeOff() {
takeOffBehavior.takeOff();
};
};
//2.飞机的实现
class Helicopter extends AirCraft {
public Helicopter() {
flyBehavior = new SubSonicFly();
takeOffBehavior = new VerticalTakeOff();
}
}
class AirPlane extends AirCraft {
public AirPlane() {
flyBehavior = new SubSonicFly();
takeOffBehavior = new LongDistanceTakeOff();
}
}
class Fighter extends AirCraft {
public Fighter() {
flyBehavior = new SuperSonicFly();
takeOffBehavior = new LongDistanceTakeOff();
}
}
class Harrier extends AirCraft {
public Harrier() {
flyBehavior = new SuperSonicFly();
takeOffBehavior = new VerticalTakeOff();
}
}
//测试主函数
public class StrategyTest {
public static void main(String[] args) {
Helicopter helicopter=new Helicopter();
helicopter.takeOff();
helicopter.fly();
AirPlane airPlane=new AirPlane();
airPlane.takeOff();
airPlane.fly();
}
}
运行结果如下:
很显然的是,在主函数中,虽然Helicopter与AirPlane使用的是同一个方法,但是其得到的结果,也就是输出是不同的。
同时在于AirCraft,如果以后各个飞机要扩展不同的功能,可以直接在里面加,在不同的飞机实现补上不同的实现就得到不同的同名类实现方法。