基于Map + bean 的策略模式实现
1、关于策略模式
定义和基本实现可以参考菜鸟教程-策略模式 他这个是基于构造方法的
2、使用Map + Bean方式实现策略模式
原有策略顶层接口不变,但是修改上下文类的构造方式,不通过set方法和构造方法去获取指定的策略实现;
我这里以商城计算商品价格写的demo;
2.1 定义顶层计算价格接口
/**
* 价格计算策略接口
*/
public interface PriceCalculatingStrategy {
/**
* 计算价格
*
* @param user 操作用户
* @param factor 影响因素
* @param prices 价格
* @return 计算后的价格
*/
BigDecimal calculatingProductPrices(User user, ProductPriceFactor factor, BigDecimal prices);
}
2.2 定义上下文
/**
* 价格计算上下文
*/
@Component
public class PricesContext {
/**
* 通过Map + bean的方式把策略实现交给spring管理
*/
@Resource(name = "priceStrategyMap")
private Map<Integer, PriceCalculatingStrategy> calculatingStrategyMap;
/**
* 计算价格
*
* @param user 用户
* @param factor 价格影响因素
* @param prices 原价
* @return 原价减去或者加上各种因素产生的价格(如邮费、会员)
*/
public BigDecimal calculating(User user, ProductPriceFactor factor, BigDecimal prices) {
PriceCalculatingStrategy priceCalculatingStrategy = calculatingStrategyMap.get(factor.getFactorType());
return priceCalculatingStrategy.calculatingProductPrices(user,factor, prices);
}
}
2.3 策略注入类(组件)
/**
* 策略配置,注入到bean中
*/
@Configuration
public class PriceStrategyConfig {
/**
* vip对原价的影响
*/
@Resource
private VIPPriceStrategy vipPriceStrategy;
/**
* 邮费对原价的影响
*/
@Resource
private PostageStrategy postageStrategy;
/**
* 策略
*
* @return 策略模式的bean容器
*/
@Bean(name = "priceStrategyMap")
public Map<Integer, PriceCalculatingStrategy> submitOrderStrategyMap() {
Map<Integer, PriceCalculatingStrategy> strategyMap = new HashMap<>();
strategyMap.put(FactorType.VIP.factorType, vipPriceStrategy);
strategyMap.put(FactorType.POSTAGE.factorType, postageStrategy);
return strategyMap;
}
/**
* 价格影响因素类型枚举
* 这里应该单独成类,demo就直接内部了
*/
@Getter
enum FactorType {
/**
* vip
*/
VIP(3),
/**
* 邮费
*/
POSTAGE(2);
FactorType(int factorType) {
this.factorType = factorType;
}
private final int factorType;
}
}
2.4 策略模式的具体实现
/**
* vip 折扣
*/
@Service
public class VIPPriceStrategy implements PriceCalculatingStrategy{
/**
* 计算价格(这里假设是打折)
*
* @param factor 影响因素
* @param prices 价格
* @return 计算后的价格
*/
@Override
public BigDecimal calculatingProductPrices(User user, ProductPriceFactor factor, BigDecimal prices) {
// TODO 忽略会员等级实现的判断 测试用固定值
return user.getId().equals(1L) ? prices.multiply(new BigDecimal("0.7")) : prices.multiply(factor.getValue());
}
}
/**
* 发货地的邮费影响价格策略
*/
@Service(value = "postageStrategy")
public class PostageStrategy implements PriceCalculatingStrategy{
/**
* 计算价格 (这里假设是在基础邮费上增加值)
*
* @param factor 影响因素
* @param prices 价格
* @return 计算后的价格
*/
@Override
public BigDecimal calculatingProductPrices(User user, ProductPriceFactor factor, BigDecimal prices) {
// TODO 测试忽略发货地 收货地之间的邮费计算 测试用固定值
return user.getId().equals(2L) ? prices.add(factor.getValue()) : prices;
}
}
2.5 策略接口调用
这里直接调用上下文的计算方式,通过指定的类型(可以看2.3的bean注入)去获取策略实现。
/**
* 商品实现层
*/
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
private final ProductPriceFactorService productPriceFactorService;
private final PricesContext pricesContext;
/**
* 计算商品价格
*
* @param productId 货物id
* @param productNum 商品数量
* @param user 计算商品的用户
* @return {@link BigDecimal} 商品最后的价格
*/
public BigDecimal calculatingProductPrices(Long productId, Integer productNum, User user) {
//TODO 测试我这里忽略参数的校验
Product product = this.getById(productId);
BigDecimal prices = product.getPrice().multiply(new BigDecimal(productNum));
prices = calculatingFactor(user, productId, prices);
return prices;
}
/**
* 计算各种因素影响的价格
* @param user 计算商品的用户
* @param productId 产品id
* @param prices 价格
* @return 计算后的价格
*/
private BigDecimal calculatingFactor(User user, Long productId, BigDecimal prices) {
List<ProductPriceFactor> allFactorByProDuct = productPriceFactorService.getAllFactorByProDuct(productId);
if (CollectionUtils.isNotEmpty(allFactorByProDuct)) {
for (ProductPriceFactor factor : allFactorByProDuct) {
prices = pricesContext.calculating(user, factor, prices);
}
}
return prices;
}
}
2.6 测试用例
2.7 额外
本demo基于springboot + mysql + maven + mybatisplus实现,写的不是很好,不吝赐教啊!!一起成长