在之前做的營銷項目中,優(yōu)惠券有滿減券和折扣券類型(后面會增加類型),這兩種類型的計算規(guī)則是不一樣的,滿減是用減法,折扣是用%。如果用if(滿減){}else if(折扣){}來處理,那么就顯得很low
這種場景使用了策略+模板方法+工廠。策略就是替代了 if else ,模板方法是將滿減券和折扣券都需要用到的邏輯寫到抽象父類上讓這兩種類型繼承,就可以復用方法,工廠主要是通過spring的ioc注入來實現(xiàn)。
直接代碼展示
首先定義優(yōu)惠券計算的接口
public interface ICouponCalculate {
/**
* 優(yōu)惠計算方法定義
*/
CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO);
/**
* 計算規(guī)則對應的枚舉
*
* @return
*/
MarketingTypeEnum calculateType();
// 這里主要是當獲取不到對應優(yōu)惠券類型的策略類,就默認獲取這個類來報錯提示
ICouponCalculate DEFAULT_IMPLEMENT = new ICouponCalculate() {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
throw new UnsupportedOperationException();
}
@Override
public MarketingTypeEnum calculateType() {
throw new UnsupportedOperationException();
}
};
}
然后定義策略類的優(yōu)惠券計算的抽象父類 實現(xiàn)優(yōu)惠券計算的接口
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;
// 美元的優(yōu)惠金額必須滿0.01元,不然不能使用這張優(yōu)惠券,HKR必需滿1元
// 這個方法滿減券和折扣券都需要用到,所以寫到父類上
protected boolean isDiscount(CurrencyTypeEnum currencyType, int calculateKHR, double calculateUSD) {
if (currencyType.equals(CurrencyTypeEnum.KHR)) {
if (calculateKHR < MIN_KHR) {
// KHR少于1元,不返現(xiàn)
log.info("KHR優(yōu)惠金額小于1");
return false;
}
}
if (currencyType.equals(CurrencyTypeEnum.USD)) {
if (calculateUSD < MIN_USD) {
// USD少于0.01元,不返現(xiàn)
log.info("USD優(yōu)惠金額小于0.01");
return false;
}
}
return true;
}
然后寫具體類型的策略類,繼承抽象父類
滿減策略類
@Component
public class FullCouponCalculateStrategy extends CouponCalculateAbstract {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
log.info("滿減優(yōu)惠券計算");
......
return calculateResultDTO;
}
@Override
public MarketingTypeEnum calculateType() {
return MarketingTypeEnum.FULL_COUPON;
}
}
折扣策略類
@Component
public class DiscountCouponCalculateStrategy extends CouponCalculateAbstract {
@Override
public CalculateResultDTO calculate(RulesExecuteReqDTO rulesExecuteReqDTO) {
log.info("折扣優(yōu)惠券計算");
業(yè)務代碼省略......
return calculateResultDTO;
}
@Override
public MarketingTypeEnum calculateType() {
return MarketingTypeEnum.DISCOUNT_COUPON;
}
}
運行策略的Context類,首先通過構造方法IOC注入方式獲取到所有的優(yōu)惠券計算實現(xiàn)類,然后封裝map中 key對應類型的枚舉,value為具體實現(xiàn)類。這個map相當于策略類的工廠
@Component
public class CouponCalculateStrategyContext {
// 定義map,優(yōu)惠券類型對應計算類
Map<MarketingTypeEnum, ICouponCalculate> calculateMap = new EnumMap<>(MarketingTypeEnum.class);
// 初始化calculateMap,將對應的關系存到calculateMap中
@Autowired
public CouponCalculateStrategyContext(final Map<String, ICouponCalculate> instanceMap) {
// 將Map<String, ICalculate> calculateInstance傳成對應計算規(guī)則的枚舉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);
}
// 執(zhí)行策略方法
public CalculateResultDTO doCouponCalculate(MarketingTypeEnum marketingType, RulesExecuteReqDTO rulesExecuteReqDTO) {
ICouponCalculate couponCalculate = calculateMap.getOrDefault(marketingType, DEFAULT_IMPLEMENT);
return couponCalculate.calculate(rulesExecuteReqDTO);
}
}