策略模式是设计模式中很重要的一种,它的主要意图就是:定义了算法族,分别封装起来,让它们之间可以互相替换。它让算法的变化可以独立于使用算法的客户,使得我们可以随时更改它们而不影响客户端的代码,而客户端可以自由选择不同的算法执行。
要想了解策略模式,我们就要理解几个重要概念:
public abstract class Plane{ private abstract void fly(); private abstract void attack(); }
接着我们就开始定义一些具体型号的战斗机:
public class RocketPlane extends Plane{ private void fly(){ System.out.println("This plane fly with Rocket"); } private void attack(){ System.out.println("This plane attack with fire"); } } public class WindPlane extends Plane{ private void fly(){ System.out.println("This plane fly with wind"); } private void attack(){ System.out.println("This plane attack with Rocket"); } }
然后就在我们的程序中这样写:
public static void main(String[] args){ RocketPlane plane1 = new RocketPlane(); WindPlane plane2 = new WindPlane(); showFunctionOfPlane(plane1); showFunctionOfPlane(plane2); } private void showFunctionOfPlane(Plane plane){ plane.fly(); plane.attack(); }
使用继承可以解决这个问题,但是,继承也有它自己的问题。继承最大的问题就是,基类的改变会传给所有的子类,这是我们类设计者不想看到的。那么,不使用继承不就可以了?接口,就是我们这种情况下最好的替代方案。
public Interface Plane{ void fly(); void attack(); }
这样就将具体的实现交给实现类,从而避免我们上面的问题。确实如此,但不同型号的战斗机,就算外观差距太大,基本的东西都是不变的,像是重量这些基本的属性,至少在很长的一段时间都不会发生变化,如果用接口的话,我们就不能设置一些共同的属性和方法,当然我们可以将这样的东西交给实现类来实现,这样,代码重复的程度太可怕了!
public Interface FlyAble{ void fly(); } public Interface AttackAble{ void attack(); }
public class RocketPlane extends Plane implements FlyAble, AttackAble{ void fly(){
System.out.println("This plane fly with Rocket");
} void attack(){
System.out.println("This plane attack with fire");
} } public class WindPlane extends Plane implements FlyAble, AttackAble{ void fly(){
System.out.println("This plane fly with wind");
} void attack(){
System.out.println("This plane attack with Rocket");
} }
为什么会这样写?很简单,因为我们可能有些飞机根本不具有飞行能力,像是这样:
public class NotFlyPlane extends Plane implements AttackAble{ void attack(){
System.out.println("This Plane attack with wind");
} }
但是,根本不需要我们的子类实现这些接口,接口更大的意义是对象组合,这样根本就失去了接口的优点。要想利用接口的这些优点,我们可以这样建立这两个接口的实现类组,像是这样:
public class FlyWithRocket implements FlyAble{ void fly(){
System.out.println("This plane fly with rocket");
} }
public class AttackWithRocket implements AttackAble{ void attack(){
System.out.println("This Plane attack with rocket");
} }
public class FlyWithWind implements FlyAble{
void fly(){
System.out.println("This plane fly with wind");
}
}
public class AttackWithFire implements AttackAble{
void attack(){
System.out.println("This plane attack with fire");
}
}
public class NotFly implements FlyAble{
void fly(){
System.out.println("This plane can't fly");
}
}
然后再在我们的代码中使用这些实现类:
public abstract class Plane(){
protected FlyAble mFly;
protected AttackAble mAttack;
protected abstract void description();
protected void functionTest(){
mFly.fly();
mAttack.attack();
}
}
public class RocketPlane extends Plane{ RocketPlane(){
super.mFly = new FlyWithRocket(); super.mAttack = new AttackWithFire();
}
protected void description(){
System.out.println("I am a RocketPlane");
}
}
public class test{
public static void main(String[] args){
RocketPlane plane = new RocketPlane();
plane.functionTest();
}
}
这就是使用对象组合的方式,但是这样的方式还不够优雅。这时,策略模式就正式登场了,因为它就是处理对象组合的一种模式。
public abstract class Plane {
private FlyAble mFly;
private AttackAble mAttack;
Plane() { }
Plane(FlyAble fly, AttackAble attack) {
this.mFly = fly;
this.mAttack = attack;
}
protected abstract void description();
protected void setFly(FlyAble fly) {
this.mFly = fly;
}
protected void setAttack(AttackAble attack) {
this.mAttack = attack;
}
protected void testFunction() {
description();
mFly.fly();
mAttack.attack();
}
}
接着是我们的子类和测试类:
public class RocketPlane extends Plane {
RocketPlane() { }
RocketPlane(FlyAble fly, AttackAble attack) {
super(fly, attack);
}
@Override
protected void description() {
System.out.println("I am a RocketPlane");
}
}
public class test{
public static void main(String[] args){
RocketPlane plane = new RocketPlane(new FlyWithRocket(), new AttackWithFire());
plane.testFunction();
}
}
plane.setFly(new FlyWithWind());
public class FunctionTest{ private Plane mPlane; FunctionTest(Plane plane){ this.mPlane = plane; } void functionTest(){ plane.testFunction(); } }
public class test{
public static void main(String[] args){
RocketPlane plane = new RocketPlane(new FlyWithRocket(), new AttackWithFire());
FunctionTest test = new FunctionTest(plane);
test.functionTest();
}
}
使用委托类到底有什么好处? 委托类提供的就是一个间接层,我们不需要知道有关于战斗机的具体细节,我们只知道,使用functionTest()就可以让我们的战斗机飞起来,攻击敌人。这就是封装,客户只知道调用委托类提供的方法就可以,就算战斗机的内部构造发生变化,像是testFunction()变成function(),又和我们客户代码有什么关系呢?
