什么是策略模式?
根据《设计模式之禅》的定义:
定义一组算法,并把这些算法封装起来,然后使它们可以互换
这里的算法我们可以理解为类处理某个业务的方法,而我们都知道,处理同一个业务可能会有不同的策略。
为什么要用策略模式?
如策略模式的定义所言,这种模式会把处理某个业务的不同方法封装成不同的类,然后可以根据调用者的状态选择合适的策略。调用者也可以随时切换到不同的模式下,但不改变业务类本身的代码。
下面举一个旅游的例子,根据我们的预算可以选择不同的出行方式,比如高铁、飞机、自驾游……如果没有策略模式,我们大概会有这么一个类
public class Travel {
private int budget;
public Travel(int budget) {
this.budget = budget;
}
public void go() {
if (budget < 500) {
System.out.println("坐高铁……");
} else if (budget>=500 && budget < 1000) {
System.out.println("自驾游……");
} else {
System.out.println("坐飞机……");
}
}
public static void main(String[] args) {
Travel travel = new Travel(500);
travel.go();
}
}
上面这段代码里,travel类中有太多的if else判断,但其实这个预算的判断不应该是这个类的职责,这个类只需要负责旅游出行的相关逻辑就可以了,而决定用哪种出行方式是调用者(main函数)去决定的东西。而你会发现这段代码很难提取到调用者中。
这时候就需要策略模式了。
如何应用策略模式?
首先,策略模式中有三个固定的角色,分别是:
- Strategy Implements(策略具体实现):对不同算法进行封装
- Context(上下文对象):屏蔽高层模块对策略对象的直接访问
- Strategy Interface(策略接口):不同策略的共同接口,负责衔接Context和策略具体实现。
那么我们用策略模式重新设计上面的代码就会由这三部分构成
Strategy Inteface
public interface TravelWayStrategy{
// 负责提供具体策略实现类的接口
void go();
}
Strategy Implements
public class HighSpeedRailStrategy implements TravelWayStrategy {
public HighSpeedRailStrategy() {
// constructor code
}
@Override
public void go() {
System.out.println("坐高铁……");
}
}
public class PlaneStrategy implements TravelWayStrategy {
public PlaneStrategy() {
// constructor code
}
@Override
public void go() {
System.out.println("坐飞机……");
}
}
public class SelfDrivingStrategy implements TravelWayStrategy {
public SelfDrivingStrategy() {
// constructor code
}
@Override
public void go() {
System.out.println("自驾游……");
}
}
Context
public class Travel {
TravelWayStrategy strategy;
public void setStrategy(TravelWayStrategy strategy) {
this.strategy = strategy;
}
public void go() {
strategy.go();
}
}
然后在调用者就可以根据自己的预算选择不同的出行方式了
public class Test {
public static void main(String[] args) {
int budget = 500;
Travel travel = new Travel();
if (budget < 500) {
travel.setStrategy(new HighSpeedRailStrategy());
} else if (budget>=500 && budget < 1000) {
travel.setStrategy(new SelfDrivingStrategy());
} else {
travel.setStrategy(new PlaneStrategy());
}
travel.go();
}
}
上面的代码我们就把budget判断和travel出行类解耦了,由调用者来确定出行方式,travel出行类只需要用我们指定好的出行方式完成自己分内职责就好了。
总结
一个算法接口,任意个实现了算法接口的具体实现类和一个持有算法接口对象的上下文对象,就能实现策略模式。
当然我们也必须承认策略模式也有不足的地方:
- 调用类必须知道所有可选择的策略的具体实现类以及它们之间的区别,以便能选择合适的策略。换言之,策略模式只适用于调用者知道具体的算法的实现类的情况。
- 如果备选的策略实现类很多的话,对象的数目会很可观。