六、策略模式
策略模式
一、什么是策略模式
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。
UML结构图如下:
其中,Context是上下文,维护了一个对Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。
1. Context上下文
Context上下文角色,也叫Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
public class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
//上下文接口
public void contextInterface() {
strategy.algorithmInterface();
}
}
2. 策略角色
抽象策略角色,是对策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。algorithm是“运算法则”的意思。
public abstract class Strategy {
//算法方法
public abstract void algorithmInterface();
}
3. 具体策略角色
用于实现抽象策略中的操作,即实现具体的算法,下方用print代替。测试类共3个ConcreteStrategy,其它两个类与ConcreteStrategyA同理,就不再赘述了。
public class ConcreteStrategyA extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法A实现");
}
}
4. Client客户端
下面依次更换策略,测试一下策略模式。
public class Client {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
/**测试结果
算法A实现
算法B实现
算法C实现
*/
二、策略模式的应用及优缺点
应用场景
- 多个类只有算法或行为上稍有不同的场景
- 算法需要自由切换的场景
- 需要屏蔽算法规则的场景
优点:
- 算法可以自由切换
- 避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
- 扩展性良好,增加一个策略只需实现接口即可
缺点:
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 所有的策略类都需要对外暴露
三、策略模式案例
我们来模拟一个下班回家的场景,需要自己选择不同的交通工具来回家
1、上下文类
首先声明一个TravelContext对象,通过构造方法,传入具体的交通工具。
public class TravelContext {
private Vehicle vehicle;
public TravelContext(Vehicle vehicle){
this.vehicle = vehicle;
}
public void goHome(){
if (vehicle!=null){
vehicle.travel();
}
}
}
2、交通工具抽象类
public interface Vehicle {
void travel();
}
3、不同的交通工具类
public class Bus implements Vehicle {
public void travel() {
System.out.println("乘坐巴士");
}
}
public class Car implements Vehicle {
public void travel() {
System.out.println("乘坐小汽车");
}
}
public class Taxi implements Vehicle {
public void travel() {
System.out.println("乘坐出租车");
}
}
4、Client客户端
下面写一个简单的程序测试一下上方编写的代码。
public class Client {
public static void main(String[] args) {
TravelContext travelContext = null;
System.out.println("请选择回家乘坐的交通工具:1.小汽车 2.出租车 3.巴士");
Scanner scanner = new Scanner(System.in);
int input = scanner.nextInt();
switch (input){
case 1:
travelContext = new TravelContext(new Car());
travelContext.goHome();
break;
case 2:
travelContext = new TravelContext(new Taxi());
travelContext.goHome();
break;
case 3:
travelContext = new TravelContext(new Bus());
travelContext.goHome();
break;
default:
System.out.println("请输入1/2/3");
break;
}
}
}
/**测试结果
请选择回家乘坐的交通工具:1.小汽车 2.出租车 3.巴士
3
乘坐巴士
*/