战略
策略模式可以说是我们业务开发中使用最频繁的设计模式之一,它能让我们的代码符合开闭原则,同时业务逻辑更加内聚。
通常我们会将我们的业务逻辑抽象成一个接口,针对不同的模式,使用不同的实现。
以下单场景的价格计算为例
在使用策略模式之前,我们的代码可能是这样
if(里程包){
//计算价格逻辑为根据车辆合同价选择对应单价*购买公里数
}else if(保险){
//保险合约中剩余天数/365*保险单价
}else if(普通商品){
//商品单价*件数*折扣
}
...
而使用策略模式后,我们将价格计算抽象成PriceCalculateStrategy接口
public interface PriceCalculateStrategy {
Long calculate(Object order);
}
使用时,从策略容器中获取对应策略实现,进行调用
PriceCalculateStrategy strategy = strategyContainer.get(商品类型)
price = strategy.calculate(...)
这样做的好处是,当计算逻辑需要扩展时,我新增对应的接口实现即可,不影响整体流程。
战术
在战术层面,我们需要根据使用场景来实现我们的策略容器,来获取我们的策略实现进行调用
简单的逻辑封装
在这种场景下,我们的策略逻辑不依赖于spring ioc容器,只是单纯的业务逻辑,这种场景下推荐使用枚举来实现策略模式
public enum PriceCalculateStrategyContainer{
FRUIT(new FruitPriceCalculateStrategy()),
VEGETABLE(new VegetablePriceCalcualteStrategy());
private PriceCalculateStrategy priceCalculateStrategy;
public PriceCalculateStrategy getPriceCalculateStrategy() {
return priceCalculateStrategy;
}
PriceCalculateStrategyContainer(PriceCalculateStrategy priceCalculateStrategy) {
this.priceCalculateStrategy = priceCalculateStrategy;
}
}
调用方式如下
PriceCalculateStrategyContainer.FRUIT.getPriceCalculateStrategy().calculate(123)
依赖ioc容器的复杂模式
在spring容器中使用策略模式我们最常见的做法是
- 定义策略接口和策略实现
- 给策略实现加上特定注解
- 通过ApplicationContextAware从spring容器中获取所有策略实现,放到一个Map中
- 业务代码中从Map中获取策略实现进行调用
有没有发现你在你项目中的实现和上面的流程很相似?
在我做系统重构时,我写了很多策略模式,因此我沉淀出了一个框架来方便大家在spring容器中使用策略模式。这个策略模式框架在功能上以及稳定性上都要比自己写的强!
下面我会从术语,特性,以及基础使用来介绍我的这个框架。
术语
-
策略接口
根据业务逻辑抽象的策略接口
-
策略实现
策略接口的实现
-
策略容器
每个策略接口会对应一个策略容器,它就是个Map,用于保存策略标识符和策略实现的关系
-
策略自定义注解
策略实现上的注解,用于获取策略标识符
-
策略标识符
从策略注解上解析得到,也可以手动注册,与策略实现多对一绑定
-
策略标识符提取逻辑
从策略实现类上注解提取策略标识符的逻辑
特性
- 基础功能,策略自定义注解绑定策略实现,通过策略标识符从策略容器获取策略实现
- 支持默认策略,通过策略标识符获取不到策略实现,返回默认实现
- 策略自定义注解支持Repeatable,也就是多个标识符能绑定一个策略
- 支持手动注册策略,而不是通过注解的方式
- 提供多策略容器,一个标识符返回多个策略(比如校验场景)
基础使用
更多使用方式,见github.com/dsc-cmt/spr…,欢迎大家fork