須要基於規則篩選過濾對象的一種通用代碼實現方案

須要基於規則篩選過濾對象的一種通用代碼實現方案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" # 下單頁查詢優惠券 關閉(即忽略此規則) 提交訂單 開啓(需校驗此規則)
}

參考文檔

http://www.baeldung.com/sprin...

相關文章
相關標籤/搜索