借助强大的Spring,优雅地使用策略模式
啥是佩奇 策略模式
定义:指对象有某个行为,但是在不同的 场景 中,该行为有不同的 实现算法。
主要解决:在有多种算法相似的情况下,使用if...else...
所带来的复杂和难以维护。关键代码:实现同一个接口。 应用场景
public Integer getResult(Integer num1, Integer num2, OperationTypeEnum typeEnum) { // 判断操作类型 if (OperationTypeEnum.ADD == typeEnum) { // 相加 return num1 + num2; } else if (OperationTypeEnum.SUBTRACT == typeEnum) { // 相减 return num1 - num2; } else if (OperationTypeEnum.MULTIPLY == typeEnum) { // 相乘 return num1 * num2; } throw new RuntimeException("没有对应的操作类型");}复制代码
场景:有两个Integer类型的数num1和num2,根据入参的操作类型不同(场景不同),执行相应的相加、减、乘处理逻辑(实现算法)。这样我们的应用场景就跟上面说的策略模式定义就对应上了。
缺点:随着实现逻辑的 复杂 化,以及操作类型的 扩展,if...else...
逻辑块会越来越臃肿,也越来越 不易维护。 优雅的策略模式
中针对上述场景实现了一套经典的策略模式解决方式。
不过本文意在借助 Spring的@Autowired
注解可以直接注入类的集合类型 这一特点,优雅地实现策略模式。 - 相加、相减、相乘三种操作方式实现同一个接口
OperationService
的同一方法doOperation()
。
public interface OperationService { /** * 执行操作 * * @param num1 * @param num2 * @return */ Integer doOperation(Integer num1, Integer num2);}复制代码
@Service("addOperationServiceImpl")public class AddOperationServiceImpl implements OperationService { /** * 执行相加操作 * * @param num1 * @param num2 * @return */ @Override public Integer doOperation(Integer num1, Integer num2) { return num1 + num2; }}复制代码
@Service("subtractOperationServiceImpl")public class SubtractOperationServiceImpl implements OperationService { /** * 执行相减操作 * * @param num1 * @param num2 * @return */ @Override public Integer doOperation(Integer num1, Integer num2) { return num1 - num2; }}复制代码
@Service("multiplyOperationServiceImpl")public class MultiplyOperationServiceImpl implements OperationService { /** * 执行相乘操作 * * @param num1 * @param num2 * @return */ @Override public Integer doOperation(Integer num1, Integer num2) { return num1 * num2; }}复制代码
- 三种操作的 类型 和操作 实现类Bean的name,维护到枚举
OperationTypeEnum
中作为字典使用。
public enum OperationTypeEnum { /** * 相加 */ ADD(1, "相加", "addOperationServiceImpl"), /** * 相减 */ SUBTRACT(2, "相减", "subtractOperationServiceImpl"), /** * 相乘 */ MULTIPLY(3, "相乘", "multiplyOperationServiceImpl"); /** * 唯一编码 */ private Integer code; /** * 描述 */ private String desc; /** * 对应策略模式实现类Bean的name */ private String strategyBeanName; /* 构造方法 */ /* getter & setter */}复制代码
如上述代码,各操作实现类Bean的名字,即各实现类上方@Service
注解括号中的标识,与操作类型通过枚举OperationTypeEnum
实现了映射。
- 计算操作策略接口
CalculateOperationStrategy
只有一个方法calculate()
。 接口不再赘述,直接看实现类。
@Service("calculateOperationStrategy")public class CalculateOperationStrategyImpl implements CalculateOperationStrategy { /** * '将所有类型为OperationService的Bean注入为一个Map * key为Bean的name */ @Autowired private MapoperationServiceMap; /** * 计算 * * @param num1 * @param num2 * @param type * @return */ @Override public Integer calculate(Integer num1, Integer num2, OperationTypeEnum type) { // 该操作类型对应的策略模式实现类Bean的name String strategyBeanName = type.getStrategyBeanName(); if (operationServiceMap.get(strategyBeanName) != null) { // 执行对应策略模式实现类的doOperation方法 return operationServiceMap.get(strategyBeanName).doOperation(num1, num2); } else { throw new RuntimeException("没有对应的操作类型"); } }复制代码
- 我们通过
@Autowired
接口直接将所有类型为OperationService
的Bean注入为一个Map,Map的 key 为 Bean的name。该步骤的具体实现原理请看我的上一篇文章:。 - 刚已知传入的操作类型枚举
OperationTypeEnum
中包含对应实现类Bean的name,所以我们可以这个name作为key,从刚才的Map中get到对应操作类型的实现类,最后直接调用该实现类的doOperation()
方法。
- 最后看测试类
@RunWith(SpringRunner.class)@SpringBootTest(classes = PpValidatorApplication.class)public class CalculateOperationStrategyTest { @Autowired private CalculateOperationStrategy calculateOperationStrategy; @Test public void testCalculate() { Integer num1 = 66; Integer num2 = 6; System.out.println("计算方式:" + OperationTypeEnum.ADD.getDesc() + " ---> 计算结果:" + calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.ADD)); System.out.println("计算方式:" + OperationTypeEnum.SUBTRACT.getDesc() + " ---> 计算结果:" + calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.SUBTRACT)); System.out.println("计算方式:" + OperationTypeEnum.MULTIPLY.getDesc() + " ---> 计算结果:" + calculateOperationStrategy.calculate(num1, num2, OperationTypeEnum.MULTIPLY)); }}复制代码
执行结果如下
计算方式:相加 ---> 计算结果:72计算方式:相减 ---> 计算结果:60计算方式:相乘 ---> 计算结果:396复制代码
!!!完美!!!
总结
- 策略模式可以根据程序上下文中类型不同,执行类型对应的实现逻辑。后续修改、替换都很方便。
- 借助 Spring的
@Autowired
注解可以直接注入类的集合类型 这一特点,可以优雅地实现策略模式。具体实现原理请戳:。- 各实现类只需要维护各自类中的
doOperation()
方法即可。- 如需扩展类型,只需要新增一个实现类,实现
OperationService
接口,并将实现类Bean的名字和类型维护到字典枚举OperationTypeEnum
中。
分享自我的简书