设计模式
本系列文章均是博主原创,意在记录学习上的知识,同时一起分享学习心得。前言
- List item
本章节介绍策略模式的原理和实现,以及应用场景和真正的设计意图。
一、原理和实现
- 策略模式的定义
定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端。
一个完整的策略模式应该包含的三部分:
- 策略的定义
- 策略的创建
- 策略的使用
1.1 策略的定义
策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。
代码如下(示例):
public interface Strategy {
void calculate();
}
public class CalculateStrategyA implements Strategy {
@Override
public void calculate() {
System.out.println("A计算公式");
}
}
public class CalculateStrategyB implements Strategy {
@Override
public void calculate() {
System.out.println("B计算公式");
}
}
1.2 策略的创建
因为策略模式会包含一组策略,在使用它们的时候,一般会通过类型来判断创建哪个策略来使用。为了封装创建逻辑,我们需要对客户端代码屏蔽创建细节。我们可以把根据type创建的逻辑抽离出来,放在工厂类中。
代码如下(示例):
public class StrategyFactory {
private static final Map<String, Strategy> strategies = new HashMap<>();
static {
strategies.put("A", new CalculateStrategyA());
strategies.put("B", new CalculateStrategyB());
}
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty");
}
return strategies.get(type);
}
}
1.3 策略的使用
策略模式在使用的过程中,有运行时动态选择或者在代码里指定使用哪种策略,一般的应用场景都是运行时动态选择策略,通过模拟场景来达到动态选择的过程。
代码如下(示例):
@Test
public void test() {
Random random = new Random();
int num = random.nextInt(10);
String type = "A";
if (num >= 5) {
type = "B";
}
Strategy strategy = StrategyFactory.getStrategy(type);
strategy.calculate();
}
二、应用场景
策略模式适用于根据不同类型待动态,决定使用哪种策略这样一种应用场景。
我们可以通过策略模式来移除if-else分支判断。实际上,这得益于策略工厂类,更本质上讲,是借助查表法type查表替代根据type分支判断。
- 应用场景一举例
比如有一个超市在搞活动,购买金额小于50元,折扣为9.8;购买金额大于等于50元,且小于200元,折扣为9.5;购买金额大于等于200小于500,折扣为9折;大于500统一折扣为8折;
为了实现这么一个折扣计算功能,代码需要写4个if-else,如果需求再增多一个规则,代码还需重构if-else,这样在可维护性、可读性大大降低,而且修改容易出bug。
如果运用策略模式,每个规则对应一个策略,根据金额大小对应选择哪一种策略,这样整体代码逻辑清晰,而且不管新增或修改规则时,只需要新增或调整对应的规则策略,这样大大降低bug的风险,可维护性更高。
总结
策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对应复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入bug的风险。