策略模式(扩展Spring 依赖注入)

策略模式(扩展Spring 依赖注入)

介绍

策略模式(Strategy Pattern):封装了不同的算法,根据需求选择其一
简称:多选一
核心是上下文

使用场景

多选一适合策略模式,比如计算(加减乘除)、支付(微信、支付宝、数字人民币等)

案例

接口

public interface Calculator {
    double cal(double numA,double numB);
}

实现类

@Bean("add")
public class AddCalculator implements Calculator{
    public double cal(double numA, double numB) {
        BigDecimal a = new BigDecimal(String.valueOf(numA));
        BigDecimal b = new BigDecimal(String.valueOf(numB));
        return a.add(b).doubleValue();
    }
}
@Bean("div")
public class DivCalculator implements Calculator{
    public double cal(double numA, double numB) {
        BigDecimal a = new BigDecimal(String.valueOf(numA));
        BigDecimal b = new BigDecimal(String.valueOf(numB));
        return a.divide(b).doubleValue();
    }
}
@Bean("mul")
public class MulCalculator implements Calculator{
    public double cal(double numA, double numB) {
        BigDecimal a = new BigDecimal(String.valueOf(numA));
        BigDecimal b = new BigDecimal(String.valueOf(numB));
        return a.multiply(b).doubleValue();
    }
}
@Bean("sub")
public class SubCalculator implements Calculator{
    public double cal(double numA, double numB) {
        BigDecimal a = new BigDecimal(String.valueOf(numA));
        BigDecimal b = new BigDecimal(String.valueOf(numB));
        return a.subtract(b).doubleValue();
    }
}

上下文类

  1. 找到算法(调用容器工厂)
  2. 调用算法返回结果
public class Context {
    private static String PKG_NAME = "top.lldwb.StrategyPattern";
    private static ContainerFactory containerFactory;

    static {
        containerFactory = new ContainerFactory(PKG_NAME);
    }

    public double executeCalculator(String type, double numA, double numB) {
        Calculator calculator = containerFactory.getBean(type);
        if (calculator == null) {
            throw new RuntimeException("并没有找到计算方法");
        }
        return calculator.cal(numA, numB);
    }
}

上下文类(使用Spring的依赖注入)

注入 map 集合中,spring 会将 所有实现类 注入集合中
集合中 key(Bean的id) value(实现类的对象)
根据集合中的 value 类型去进行查找并注入依赖

为什么不使用 List 而是使用 Map,因为 List 不能存储 Bean 的 ID

public class Context {
    private final Map<String,Calculator> map;

    public double executeCalculator(String type, double numA, double numB) {
        Calculator calculator = map.get(type);
        if (calculator == null) {
            throw new RuntimeException("并没有找到计算方法");
        }
        return calculator.cal(numA, numB);
    }
}

测试

public class Test {
    @org.junit.jupiter.api.Test
    public void test(){
        Context context = new Context();
        double num = context.executeCalculator("add",1,1);
        System.out.println(num);
        System.out.println(context.executeCalculator("add",1,1));
        System.out.println(context.executeCalculator("div",1,1));
        System.out.println(context.executeCalculator("mul",1,1));
        System.out.println(context.executeCalculator("sub",1,1));
    }
}
输出
2.0
2.0
1.0
1.0
0.0

优缺点

优点

  1. 算法可以自由切换
  2. 扩展性高

缺点

  1. 默认的简单工厂会有开闭原则的问题,但是使用容器工厂就不会有开闭原则的问题
  2. 如果算法多