须要基于规则筛选过滤对象的一种通用代码实现方案spring
下单页查询优惠券列表数据库
查询当前可用的全部优惠券express
筛选符合条件的优惠券app
校验类目 通用券或者与商品类目相同单元测试
校验满减券 如满100减50 订单金额需满100可用测试
校验店铺券 不能使用其余店铺的店铺券code
// 下单页查询可用优惠券 public List<Coupon> getAvailableCoupons(String productCategory, int orderPrice, String shopId, String userId){ // 查询全部可用优惠券 List<Coupon> couponList = couponMapper.queryCoupons(userId); // 筛选优惠券 List<Coupon> availableList = new ArrayList<>(); for (Coupon coupon : couponList) { // 校验类目券 如图书券不可用于购买手机 if(!checkCategory(coupon,productCategory)){ // 类目不匹配 continue; } // 校验满减券 如满100减50 if(!checkPrice(coupon,orderPrice)){ // 订单金额不足满减金额 continue; } // 校验店铺券 if(!checkShopCoupon(coupon,shopId)){ // 排除其余店铺的优惠券 continue; } availableList.add(coupon); } return availableList; }
单元测试不方便 如想测试校验店铺券失败的状况 即便校验经过了 也不能肯定确实调用了checkShopCoupon
有多是checkCategory
失败了或者checkPrice
失败致使的 即没办法仅仅针对某一种校验进行充分测试orm
扩展不方便 如想新增一个筛选条件 如图书类目不可以使用平台券 就得修改代码 添加一个以下的校验 而后发布上线 之后要取消该用券限制 也得一样修改代码 发布上线对象
if(!checkBookCategory(productCategory,couponFrom)){ // 校验图书类目 不可以使用平台券 continue; }
经过配置规则的方式来筛选优惠券 如使用spel
来配置上述规则开发
校验类目规则 不是通用券且不等于做品类目 排除 category != 'all' and category != productCategory
校验满减金额规则 满减券且订单金额不足满减金额 排除 fullPrice != null and orderPrice < fullPrice
校验店铺券规则 店铺券且所属店铺不一样于做品的 排除 couponFrom == 'shop' and couponShopId != productShopId
筛选优惠券前 查询上述规则列表 并转为Rule对象 此时代码以下所示
public List<Coupon> getAvailableCoupons2(String productCategory, int orderPrice, String shopId, String userId){ // 查询全部可用优惠券 List<Coupon> couponList = couponMapper.queryCoupons(userId); // 筛选优惠券 List<Coupon> availableList = new ArrayList<>(); // 从数据库查询出优惠券过滤规则配置 String rules = couponMapper.getFilterRules(); List<CouponFilterRule> couponFilterRules = convertToFilterRules(rules); outer:for (Coupon coupon : couponList) { for (CouponFilterRule rule : couponFilterRules) { // 遍历规则 一旦知足 就排除 if(rule.matches(coupon)){ continue outer; } } availableList.add(coupon); } return availableList; }
单元测试友好 能够灵活自由的测试某一种校验 没有其余校验的干扰 如仅测试校验类目
// coupon1 通用券 coupon2 类目券等于商品类目 coupon3 类目券且不一样于商品类目【被排除】 when(couponMapper.queryCoupons(userId)).thenReturn(newArrayList(coupon1,coupon2,coupon3)); when(couponMapper.getFilterRules()).thenReturn("category != 'all' and category != productCategory"); // 验证应该返回2个优惠券 assertEquals(2, availableList.size()); // 校验ID应该是1,2 ...
扩展方便 如想增长一个校验规则 如图书类目不支持使用平台券 只需增长一个配置规则便可 以下所示
productCategory == 'book' and couponFrom == 'platform'
无需任何代码开发和上线 之后去掉该规则也方便
为了支持spel
表达式 Coupon对象中须要冗余订单金额 做品类目 做品所属店铺Id等信息
可能须要基于命中不一样的规则 返回不一样的提示 如类目不匹配 订单金额不足等
提交订单也须要校验使用的优惠券是否合法 有些场景要求下单页查询优惠券不限制 提交订单时才限制 如老版本不支持用券 下单页能够选择优惠券 但提交订单失败 提示用户去升级版本
规则配置增长对应的文案 和 场景开闭状态 如
{ "rule": "not checkVersion(3.0.0)", # 版本小于3.0.0不支持用券 "message": "你当前的版本过旧不支持使用优惠劵,请更新版本", # 提示文案 "switchStatus": "01" # 下单页查询优惠券 关闭(即忽略此规则) 提交订单 开启(需校验此规则) }