JavaSpringBoot

一、策略模式代码实践

在介绍 SpringBoot 中如何实现策略设计模式之前,先简单的回顾一下策略模式的设计思路。
以编写一个简单的程序计算器,代码如下!

  • 首先,定义一个**Operation**接口,用于逻辑的计算

    1. public interface Operation {
    2. /**
    3. * 执行计算
    4. * @param a
    5. * @param b
    6. * @return
    7. */
    8. int execute(int a, int b);
    9. }
  • 接着,分别将四个if判断逻辑独立成一个模块,来单独处理 ```java public class AddOperation implements Operation {

    @Override public int execute(int a, int b) {

    1. return a + b;

    } }

public class SubOperation implements Operation {

  1. @Override
  2. public int execute(int a, int b) {
  3. return a - b;
  4. }

}

public class MultiOperation implements Operation {

  1. @Override
  2. public int execute(int a, int b) {
  3. return a * b;
  4. }

}

public class DivOperation implements Operation {

  1. @Override
  2. public int execute(int a, int b) {
  3. return a / b;
  4. }

}

  1. - **然后,创建一个工厂类,用于处理客户端传入的参数**
  2. ```java
  3. public class OperatorFactory {
  4. private static Map<String, Operation> operationMap = new HashMap<>();
  5. static {
  6. //初始化实现类
  7. operationMap.put("add", new AddOperation());
  8. operationMap.put("sub", new SubOperation());
  9. operationMap.put("multi", new MultiOperation());
  10. operationMap.put("div", new DivOperation());
  11. // more operators
  12. }
  13. /**
  14. * 获取对应的目标实现类
  15. * @param operator
  16. * @return
  17. */
  18. public static Optional<Operation> getOperation(String operator){
  19. return Optional.ofNullable(operationMap.get(operator));
  20. }
  21. }
  • 最后,在需要的地方引入方法即可!

    1. public class OperatorTestMain {
    2. public static void main(String[] args) {
    3. //获取计算的目标实现类
    4. Operation targetOperation = OperatorFactory
    5. .getOperation("add")
    6. .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
    7. int result = targetOperation.execute(1, 2);
    8. System.out.println("result:" + result);
    9. }
    10. }

    以上就是一个典型的策略模式的实践思路,从代码阅读性、扩展性角度看,还是非常干净利落的。
    那么,在SpringBoot项目中,应该如何使用呢?

    二、SpringBoot 实践应用

    3.1、方案一

  • 首先,还是定义一个**Command**接口,用于方法的抽象和统一 ```java public interface Command {

    /**

    • 命令类型
    • @return */ String operateType();

      /**

    • 执行
    • @param a
    • @param b
    • @return */ Integer execute(int a, int b);

}

  1. - **接着,编写四套不同的计算处理逻辑**
  2. ```java
  3. @Component
  4. public class AddCommand implements Command {
  5. @Override
  6. public String operateType() {
  7. return "add";
  8. }
  9. @Override
  10. public Integer execute(int a, int b) {
  11. return a + b;
  12. }
  13. }
  14. @Component
  15. public class SubCommand implements Command {
  16. @Override
  17. public String operateType() {
  18. return "subtract";
  19. }
  20. @Override
  21. public Integer execute(int a, int b) {
  22. return a - b;
  23. }
  24. }
  25. @Component
  26. public class MultiCommand implements Command {
  27. @Override
  28. public String operateType() {
  29. return "multiply";
  30. }
  31. @Override
  32. public Integer execute(int a, int b) {
  33. return a * b;
  34. }
  35. }
  36. @Component
  37. public class DivCommand implements Command {
  38. @Override
  39. public String operateType() {
  40. return "divide";
  41. }
  42. @Override
  43. public Integer execute(int a, int b) {
  44. return a / b;
  45. }
  46. }
  • 然后,编写一个类似于上文的策略处理类 ```java @Component public class CalculatorService implements ApplicationContextAware {

    private Map commandMap = new ConcurrentHashMap<>();

  1. /**
  2. * 执行计算
  3. * @param operateType
  4. * @param a
  5. * @param b
  6. * @return
  7. */
  8. public int calculate(String operateType,int a, int b){
  9. Command targetCommand = Optional.ofNullable(commandMap.get(operateType))
  10. .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
  11. return targetCommand.execute(a,b);
  12. }
  13. @Override
  14. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  15. Map<String, Command> tempMap = applicationContext.getBeansOfType(Command.class);
  16. tempMap.values().forEach(source -> commandMap.put(source.operateType(), source));
  17. }

}

  1. - **最后,只需要在适当的位置应用即可!**
  2. ```java
  3. @RunWith(SpringRunner.class)
  4. @SpringBootTest
  5. public class CalculatorServiceTest {
  6. @Autowired
  7. private CalculatorService calculatorService;
  8. @Test
  9. public void test(){
  10. int result = calculatorService.calculate("add", 1,2);
  11. System.out.println("result:" + result);
  12. }
  13. }

总结:这种方案的实践,和上面介绍的思路基本上一致,不同的地方在于,当 springboot 启动时,会将对象注入到IOC容器。

3.2、方案二(推荐)

翻查Spring的ioc容器,会发现一个秘密,当一个接口有多个实现类时,Spring会自动将Strategy接口的实现类注入到这个Map中,key为bean id,value值则为对应的策略实现类。
简单的说,只需要通过@Autowired注入对象,不需要通过CalculatorService这个类进行单独配置,操作方式如下!

  • 首先,编写一个CommandFactory工厂类,用于逻辑的处理 ```java @Component public class CommandFactory {

    /**

    • Spring会自动将Strategy接口的实现类注入到这个Map中,key为bean id,value值则为对应的策略实现类 */ @Autowired private Map commandMap;
  1. /**
  2. * 执行计算
  3. * @param operateType
  4. * @param a
  5. * @param b
  6. * @return
  7. */
  8. public int calculate(String operateType,int a, int b){
  9. Command targetCommand = Optional.ofNullable(commandMap.get(operateType))
  10. .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
  11. return targetCommand.execute(a,b);
  12. }

}

  1. - **最后,直接在合适的地方使用**`**CommandFactory**`**即可!**
  2. ```java
  3. @RunWith(SpringRunner.class)
  4. @SpringBootTest
  5. public class CalculatorServiceTest {
  6. @Autowired
  7. private CommandFactory commandFactory;
  8. @Test
  9. public void test(){
  10. int result = commandFactory.calculate("addCommand", 1,2);
  11. System.out.println("result:" + result);
  12. }
  13. }

总结:方案二和方案一的不同点在于,不需要显式的编写CalculatorService策略处理类来初始化对象,Spring在初始化对象的时候,可以实现对象的注入!