策略模式学习笔记

2021-02-16  本文已影响0人  allen716

1.概念

参考《JAVA与模式》的描述:

策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

策略模式使得算法可以在不影响到客户端的情况下发生变化。

2.层次结构

3.实际案例

笔者在公司重构金额计算模块时,需要根据产品类型 + 收费代码,计算应收金额

业务逻辑如下:

原始代码是这样:

    // 产品类型
    int type = 1;
    // 往返都可以直达
    if (type == 1) {
        // 根据费率rate1 + 收费规则rule1, 计算收费代码为:001,002的款项应收金额
        return;
    }

    // 产品类型为2
    if (type == 2) {
        // 根据费率rate2 + 收费规则rule2, 计算收费代码为:001,002的款项应收金额
        return;
    }
    // 产品类型为3
    if (type == 3) {
        // 根据费率rate3 + 收费规则rule3, 计算收费代码为:001,002的款项应收金额
        return;
    }
    // 产品类型为4
    else{
        // 根据费率rate3 + 收费规则rule3, 计算收费代码为:001,002的款项应收金额
        return;
    }

4.案例优化

如果我们遇到类似于上面的需求,第一反应肯定是用if-else语句或者switch语句,根据不同的情况执行不同的代码。但是随着需求越来越复杂,这么做的缺陷就慢慢的显现了出来:除了产品类型之外,如果增加了其他判断要素,如:收费周期、标的分类等,那么就会新增分支逻辑进行判断。

随着需求的不断增加,代码的分支会越来越多,代码最终会越来越难以维护,所以策略模式出现了。

4.1原始的策略模式

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Receivables {
    private String desc;
}
public interface CalculateService {
    List<Receivables> CalculateReceivables();
}
public class CalculateServiceImpl1 implements CalculateService {

    @Override
    public List<Receivables> CalculateReceivables() {
        List<Receivables> list = new ArrayList<>();
        list.add(new Receivables("产品1应收金额: 收费项001--金额1000.00"));
        list.add(new Receivables("产品1应收金额: 收费项002--金额2000.00"));
        return list;
    }
}
@Service
public class CalculateServiceImpl2 implements CalculateService {

    @Override
    public List<Receivables> CalculateReceivables() {
        List<Receivables> list = new ArrayList<>();
        list.add(new Receivables("产品2应收金额: 收费项001--金额2100.00"));
        list.add(new Receivables("产品2应收金额: 收费项002--金额6666.00"));
        return list;
    }
}
public class CalculateStrategy {
    private static Map<Integer, CalculateService> strategyMap = new HashMap<>();

    static {
        strategyMap.put(1, new CalculateServiceImpl1());
        strategyMap.put(2, new CalculateServiceImpl2());
        strategyMap.put(3, new CalculateServiceImpl3());
        strategyMap.put(4, new CalculateServiceImpl4());
    }

    public List<String> calculate(Integer type) {
        List<Receivables> receivablesList = strategyMap.get(type).CalculateReceivables();
        List<String> collect = receivablesList.stream()
                .map(Receivables::getDesc)
                .collect(Collectors.toList());
        return collect;
    }
}
@RestController
@RequestMapping("/calculate")
@Slf4j
public class CalculateController {
    private static final Logger logger = LoggerFactory.getLogger(CalculateController.class);

    @Autowired
    private CalculateStrategy calculateStrategy;

    @GetMapping("/strategy-test")
    public void test(@RequestParam("type") String type) {
        List<String> calculate = calculateStrategy.calculate(Integer.parseInt(type));
        calculate.forEach(logger::info);
    }
}
2021-02-16 22:08:03.731  INFO 19176 --- [nio-8080-exec-1] c.q.s.controller.CalculateController     : 产品2应收金额: 收费项001--金额2100.00
2021-02-16 22:08:03.732  INFO 19176 --- [nio-8080-exec-1] c.q.s.controller.CalculateController     : 产品2应收金额: 收费项002--金额6666.00

4.2与spring结合的策略模式

4.2.1方式1

通过@Autowired + @PostConstruct 注入依赖,并将映射关系加到strategyMap中

@Service
public class CalculateStrategy {
    @Autowired
    private CalculateServiceImpl1 calculateServiceImpl1;

    @Autowired
    private CalculateServiceImpl2 calculateServiceImpl2;

    @Autowired
    private CalculateServiceImpl3 calculateServiceImpl3;

    @Autowired
    private CalculateServiceImpl4 calculateServiceImpl4;

    private static Map<Integer, CalculateService> strategyMap = new HashMap<>();

    @PostConstruct
    public void init() {
        strategyMap.put(1, calculateServiceImpl1);
        strategyMap.put(2, calculateServiceImpl2);
        strategyMap.put(3, calculateServiceImpl3);
        strategyMap.put(4, calculateServiceImpl4);
    }

//    static {
//        strategyMap.put(1, calculateServiceImpl1);
//        strategyMap.put(2, calculateServiceImpl2);
//        strategyMap.put(3, calculateServiceImpl3);
//        strategyMap.put(4, calculateServiceImpl4);
//    }

    public List<String> calculate(Integer type) {
        List<Receivables> receivablesList = strategyMap.get(type).CalculateReceivables();
        List<String> collect = receivablesList.stream()
                .map(Receivables::getDesc)
                .collect(Collectors.toList());
        return collect;
    }
}

运行结果同4.1

4.2.2方式2

具体说明:直接通过Map<String, CalculateService> 注入依赖,这里:beanName是map中的key,bean对应的接口(实现类)是map中的value

@Service("2")
public class CalculateServiceImpl2 implements CalculateService {

    @Override
    public List<Receivables> CalculateReceivables() {
        List<Receivables> list = new ArrayList<>();
        list.add(new Receivables("产品2应收金额: 收费项001--金额2100.00"));
        list.add(new Receivables("产品2应收金额: 收费项002--金额6666.00"));
        return list;
    }
}

-其次,上下文中自动注入Map<String, CalculateService>

@Service
public class CalculateStrategy {
    @Autowired
    private Map<String, CalculateService> strategyMap;

    public List<String> calculate(Integer type) {
        List<Receivables> receivablesList = strategyMap.get(String.valueOf(type)).CalculateReceivables();
        List<String> collect = receivablesList.stream()
                .map(Receivables::getDesc)
                .collect(Collectors.toList());
        return collect;
    }
}

结果同4.1

5.小结

5.1优点

5.2缺点

5.3使用场景

上一篇 下一篇

猜你喜欢

热点阅读