在之前做的营销项目中,优惠券有满减券和折扣券类型(后面会增加类型),这两种类型的计算规则是不一样的,满减是用减法,折扣是用%。如果用if(满减){}else if(折扣){}来处理,那么就显得很low
这种场景使用了策略+模板方法+工厂。策略就是替代了 if else ,模板方法是将满减券和折扣券都需要用到的逻辑写到抽象父类上让这两种类型继承,就可以复用方法,工厂主要是通过spring的ioc注入来实现。
直接代码展示
首先定义优惠券计算的接口
public interface ICouponCalculate {
/**
* 优惠计算方法定义
*/
CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO);
/**
* 计算规则对应的枚举
*
* @return
*/
MarketingTypeEnum calculateType();
// 这里主要是当获取不到对应优惠券类型的策略类,就默认获取这个类来报错提示
ICouponCalculate DEFAULT_IMPLEMENT = new ICouponCalculate() {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
throw new UnsupportedOperationException();
}
@Override
public MarketingTypeEnum calculateType() {
throw new UnsupportedOperationException();
}
};
}
然后定义策略类的优惠券计算的抽象父类 实现优惠券计算的接口
public abstract class CouponCalculateAbstract implements ICouponCalculate {
public final static double PERCENT = 0.01;
public final static double MIN_KHR = 1;
public final static double MIN_USD = 0.01;
// 美元的优惠金额必须满0.01元,不然不能使用这张优惠券,HKR必需满1元
// 这个方法满减券和折扣券都需要用到,所以写到父类上
protected boolean isDiscount(CurrencyTypeEnum currencyType, int calculateKHR, double calculateUSD) {
if (currencyType.equals(CurrencyTypeEnum.KHR)) {
if (calculateKHR < MIN_KHR) {
// KHR少于1元,不返现
log.info("KHR优惠金额小于1");
return false;
}
}
if (currencyType.equals(CurrencyTypeEnum.USD)) {
if (calculateUSD < MIN_USD) {
// USD少于0.01元,不返现
log.info("USD优惠金额小于0.01");
return false;
}
}
return true;
}
然后写具体类型的策略类,继承抽象父类
满减策略类
@Component
public class FullCouponCalculateStrategy extends CouponCalculateAbstract {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
log.info("满减优惠券计算");
......
return calculateResultDTO;
}
@Override
public MarketingTypeEnum calculateType() {
return MarketingTypeEnum.FULL_COUPON;
}
}
折扣策略类
@Component
public class DiscountCouponCalculateStrategy extends CouponCalculateAbstract {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
log.info("折扣优惠券计算");
业务代码省略......
return calculateResultDTO;
}
@Override
public MarketingTypeEnum calculateType() {
return MarketingTypeEnum.DISCOUNT_COUPON;
}
}
运行策略的Context类,首先通过构造方法IOC注入方式获取到所有的优惠券计算实现类,然后封装map中 key对应类型的枚举,value为具体实现类。这个map相当于策略类的工厂
@Component
public class CouponCalculateStrategyContext {
// 定义map,优惠券类型对应计算类
Map<MarketingTypeEnum, ICouponCalculate> calculateMap = new EnumMap<>(MarketingTypeEnum.class);
// 初始化calculateMap,将对应的关系存到calculateMap中
@Autowired
public CouponCalculateStrategyContext(final Map<String, ICouponCalculate> instanceMap) {
// 将Map<String, ICalculate> calculateInstance传成对应计算规则的枚举Map<RegisteredCashBackTypeEnum, ICalculate>
Map<MarketingTypeEnum, ICouponCalculate> collect = instanceMap.values().stream()
.filter(iCouponCalculate -> iCouponCalculate.calculateType() != null)
.collect(Collectors.toMap(ICouponCalculate::calculateType, iCouponCalculate -> iCouponCalculate));
calculateMap.putAll(collect);
}
// 执行策略方法
public CalculateResultDTO doCouponCalculate(MarketingTypeEnum marketingType, RulesExecuteReqDTO rulesExecuteReqDTO) {
ICouponCalculate couponCalculate = calculateMap.getOrDefault(marketingType, DEFAULT_IMPLEMENT);
return couponCalculate.calculate(rulesExecuteReqDTO);
}
}