基于Map+bean的策略模式实现方式
更新时间:2026年06月09日 09:32:47 作者:桔梗迷
这段文章详细介绍了策略模式的实现方法,通过构造方法和Map+Bean方式定义顶层接口、上下文类及策略实现,并结合SpringBoot、MyBatisPlus等技术栈进行了实际应用,适合编程爱好者和技术人员参考学习
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实现,写的不是很好,一起成长
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
pdf2swf+flexpapers实现类似百度文库pdf在线阅读
这篇文章主要介绍了pdf2swf+flexpapers实现类似百度文库pdf在线阅读的相关资料,需要的朋友可以参考下2014-10-10
PowerJob的DatabaseMonitorAspect源码流程
这篇文章主要为大家介绍了PowerJob的DatabaseMonitorAspect源码流程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2024-01-01
spring-boot中spring-boot-maven-plugin报红错误及解决
这篇文章主要介绍了spring-boot中spring-boot-maven-plugin报红错误及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-03-03


最新评论