GoF 定义: 定义一个系列的算法,然后封装每个算法,使得他们之间可以互换。策略模式使得算法在客户端之间可以独立地变化。(Define a family of algorithms, encapsulate each one, and make them interchangeable. The strategy pattern lets the algorithm vary independently from client to client.)
进一步解释:策略模式是把算法封装成相同的接口,然后在运行时按需动态调用。一旦有了统一接口,客户端就可用用同一份代码处理不同的情况,要做的只是在此之前设置不同的算法子类。
例如,有一个段子讲的是:“一个标准的程序员在睡觉时候都会准备两个杯子,一个是空的,一个装满了水。装满水的杯子为的是醒来之后口渴,空白杯子是为了万一醒来之后不渴。”这位哥们一看就是学过设计模式的科班出身,把策略模式用到了生活中。
我们用代码表述这个情景:
import java.util.Random;
/**
* strategy pattern
*/
public class Main {
public static void main(String[] args) {
String[] conditionArray = {"Thirsty", "NotThirsty"};
// 实例化两个算法类
IPickCup whenThirsty = new PickCupWhenThirsty();
IPickCup whenNotThirsty = new PickCupWhenNotThirsty();
WakeUp wakeUp = new WakeUp();
for (int i = 0; i < 10; i++) {
// 循环10次,随机生成口渴和不渴的情形
String condition = conditionArray[new Random().nextInt(2)];
System.out.println("\nTime "+ i + " I'm "+condition);
// 根据情况传入不同的算法
if (condition.equals("Thirsty")){
wakeUp.setPickCup(whenThirsty);
} else {
wakeUp.setPickCup(whenNotThirsty);
}
wakeUp.doRegular();
}
}
}
// 喝水动作的接口函数
abstract class IPickCup {
abstract void pickUpCup();
}
// 感觉口渴时
class PickCupWhenThirsty extends IPickCup {
@Override
void pickUpCup() {
System.out.println("Pick up the cup");
System.out.println("Drink...");
System.out.println("Put down the cup");
System.out.println("And continue go to sleep");
}
}
// 万一不渴
class PickCupWhenNotThirsty extends IPickCup {
@Override
void pickUpCup() {
System.out.println("pick up the cup");
System.out.println("Put down the cup");
System.out.println("And continue go to sleep");
}
}
class WakeUp {
IPickCup pickCup = null;
// 在这里动态加载不同的算法(即渴不渴的情况)
void setPickCup(IPickCup pickCup) {
this.pickCup = pickCup;
}
// 策略模式可以使用同一份代码处理不同的情况
void doRegular() {
System.out.println("I am waking up");
pickCup.pickUpCup();
}
}
类图:
输出:
策略模式的关键在于实现具有统一接口的算法类(这里的杯子就是接口,因此就算没有水,杯子还是要有的),然后用不同的算法类处理不同的情形(口渴和不口渴)。在调用过程中,客户端程序根据不同情形动态加载不同的算法(WakeUp 类中的setPickCup()方法)。