1.为什么会有策略模式?
当我们编写程序时,肯定会遇到一个业务场景针对不同的逻辑情况执行不同的逻辑操作,常见的就是使用if-else、switch-case语句(硬编码一一嵌套在具体的代码中了)来实现这种操作,但是众说周知多重条件语句不易维护,为了解决多重条件语句带来的这种问题,策略模式应运而生。
例如生活中常见的策略模式,出行可以打飞机、开车、做轮船等,游戏买皮肤可以用点卷、现金、皮肤碎片等都是各种实现策略。
在设计程序的时候也会遇到使用策略模式的情况,例如当实现某一个功能存在多种算法或者策略时,我们可以根据不同环境选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
在策略模式中定义一系列算法或策略,并将这些算法封装在一个一个的类中,使得它们可以互相任意替换,通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。
2.使用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现
注意:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
3.三要素
- 抽象策略类:定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略类:实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
- 环境类:维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象
4.策略模式设计
我们通过下面的实例来演示策略模式的使用。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
关键代码:实现同一个接口。
策略模式UML图
Strategy
public interface Strategy {
void method();
}
@Service(value = "strategyA")
public class StrategyA implements Strategy {
@Override
public void method() {
System.out.println("我是A策略实现方案!");
}
}
@Service(value = "strategyB")
public class StrategyB implements Strategy {
@Override
public void method() {
System.out.println("我是B策略实现方案!");
}
@Service(value = "strategyC")
public class StrategyC implements Strategy {
@Override
public void method() {
System.out.println("我是C策略实现方案!");
}
}
Context
@Component
public class StrategyContext {
private final Map<String, Strategy> strategyMap = new ConcurrentHashMap<>();
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
private void init() {
strategyMap.putAll(applicationContext.getBeansOfType(Strategy.class));
}
public Strategy getInstance(Integer code) {
String beanName = StrategyEnum.getByCode(code).getName();
return this.getInstanceByBeanName(beanName);
}
private Strategy getInstanceByBeanName(String beanName) {
if (!StringUtils.isEmpty(beanName)) {
return strategyMap.get(beanName);
}
return null;
}
}
Enum
public enum StrategyEnum{
//策略枚举类
STRATEGY_A();
STRATEGY_B();
STRATEGY_C();
private Integer code;
private String name;
public StrategyEnum(Integer code, String name){
this.code = code;
this.name = name;
}
public Integer getCode() {
return code;
}
public String getName() {
return name;
}
public static StrategyEnum getByCode(Integer code){
StrategyEnum[] values = StrategyEnum.values();
for(StrategyEnum strategyEnum : values){
if(strategyEnum.getCode().equals(code)){
return strategyEnum;
}
}
}
}
测试
@RestController
public class StrategyController {
@Autowired
private StrategyContext context;
@RequestMapping("/method")
public String method(Integer code) {
return context.getInstance(code).method();
}
结果