定义:策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
概念是挺抽象的,没有明白策略模式是怎么回事之前,只看它的定义的话,可能没什么用。一个好的例子可以帮助我们更好地理解概念。下面的例子是从《Head First 设计模式》一书来的,通过该例子我们可以对策略模式有一个初步认识。
- 首先,定义一个Duck类,该类是抽象的。
/**
* 抽象的鸭子类
*/
public abstract class Duck {
/*
* Duck 类中的接口属性,并没有提供默认值,而是在子类中去完成默认配置,所以在使用时很可能出现空指针错误
*/
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
// 不变的
public abstract void display();
// 不变的
public void swim() {
System.out.println("All ducks can swim.");
}
// 会变化的 - 委托给行为类 - 其实就是算法族
public void performFly() {
flyBehavior.fly();
}
// 会变化的 - 委托给行为类 - 其实就是算法族
public void performQuack() {
quackBehavior.quack();
}
public FlyBehavior getFlyBehavior() {
return flyBehavior;
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public QuackBehavior getQuackBehavior() {
return quackBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
从抽象类中可以看出,对于基本不会变化的方法,我们可以在抽象类中定义甚至直接在抽象类中实现,而会变化的方法,我们只是以接口的形式在抽象类中给出。
在这里,FlyBehavior和QuackBehavior接口就代表了策略模式定义中所说的算法族,这些接口的具体实现就是一个个不同的算法,或者说一个个不同的策略。
- 分别看一下我们定义的算法族以及算法
/**
* 飞的行为 - 算法族
*/
public interface FlyBehavior {
void fly();
}
/**
* 不会飞 - 具体算法
*/
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("Can not fly.");
}
}
/**
* 用翅膀飞 - 具体算法
*/
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("Fly with wings.");
}
}
/**
* 叫的行为 - 算法族
*/
public interface QuackBehavior {
void quack();
}
/**
* 正常叫 - 具体算法
*/
public class NormalQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Normally quack.");
}
}
/**
* 小声叫 - 具体算法
*/
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Silently quack.");
}
}
- 接下来的问题就是这些具体的算法该怎样应用,如下所示:
/**
* 野鸭
*/
public class MallardDuck extends Duck {
/**
* 这里做的不好 - 因为它是针对具体实现编程
*
* 见 Head First 设计模式 17 页
*/
public MallardDuck() {
/*
* 父类中的接口属性,并没有提供默认值,而是在子类中去完成默认配置,所以在使用时很可能出现空指针错误
*/
flyBehavior = new FlyNoWay();
quackBehavior = new NormalQuack();
}
@Override
public void display() {
System.out.println("This is mallard.");
}
}
可以看出,MallardDuck类是Duck的具体实现,它在自己的构造方法中引入了具体的算法(虽然这样做并不是最好的方案)。
- 测试
/**
* 设计模式
*/
public class DesignPatternTest {
/**
* 策略设计模式 - 见 Head First 设计模式 22 页
*
* 策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
*/
@Test
public void StrategyTest() {
Duck duck = new MallardDuck();
duck.display();
duck.swim();
duck.performFly();
duck.performQuack();
// 动态改变飞和叫的行为
duck.setFlyBehavior(new FlyWithWings());
duck.setQuackBehavior(new MuteQuack());
duck.performFly();
duck.performQuack();
}
}
如果看懂了上面的例子的话,到这里,脑子中应该已经可以画出本例的类图了。
补充
- 对于上面定义的野鸭类,我们可以做一个小的调整
/**
* 野鸭
*/
public class MallardDuck extends Duck {
public MallardDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
this.flyBehavior = flyBehavior;
this.quackBehavior = quackBehavior;
}
@Override
public void display() {
System.out.println("This is mallard.");
}
}
- 然后像这样为野鸭指定具体飞和叫的行为
Duck duck = new MallardDuck(new FlyWithWings(), new MuteQuack());
其实,在本例中,我们可以把MallardDuck看做是策略应用的上下文,它决定了该调用哪个具体的策略。