策略模式在公司项目中的运用实践,看完又可以涨一波实战经验了!
營銷系統(tǒng)是一個動態(tài)的、有機(jī)地結(jié)合的系統(tǒng),經(jīng)常會隨著業(yè)務(wù)的不斷變化發(fā)生調(diào)整,因此從事這一業(yè)務(wù)的開發(fā)可讓我頭疼了。
之前在工作中就不乏一次遇到過隨意調(diào)整營銷策略的情況,在部分場景下由于使用了硬編碼的方式來實現(xiàn),因此在調(diào)整策略的時候顯得特別不靈活。
下邊我列舉一個曾經(jīng)遇到過的應(yīng)用場景:
業(yè)務(wù)部門需要上線一款新型的產(chǎn)品,用戶在線上購買了對應(yīng)的產(chǎn)品,然后下單支付之后需要享受不同的服務(wù)內(nèi)容,這些服務(wù)包含了贈送優(yōu)惠券,發(fā)送紅包補(bǔ)貼,加積分,升級等服務(wù)項。并且上線之后,可能會隨著市場的因素的調(diào)整,部分服務(wù)內(nèi)容也會有所下架,后期調(diào)整因素極高。
下邊是一張用戶建模的圖:
線上買單,到選擇購買的產(chǎn)品類型,再到后續(xù)下單之后執(zhí)行不同的營銷規(guī)則,每個產(chǎn)品對應(yīng)不同的服務(wù)項目并且服務(wù)項目的內(nèi)容還可能會隨時調(diào)整。
舉個實際案例來說,線上有這么幾款服務(wù)產(chǎn)品供消費者選購:
1.999元會員套餐
正常會員服務(wù)期1個月
發(fā)放5張優(yōu)惠券
2.1999元會員套餐
正常會員服務(wù)期2個月
發(fā)放6張優(yōu)惠券
邀請新人加入app,新人在n天內(nèi)購買套餐有優(yōu)惠
3.2999元會員套餐
正常會員服務(wù)期3個月
發(fā)放7張優(yōu)惠券
滿2500元消費,返現(xiàn)50元紅包
….
大致看看,不同的產(chǎn)品對應(yīng)不同的促銷規(guī)則,似乎毫無規(guī)律可言。
但是如果通過抽象的邏輯將其中的共同部分抽取出來,就會發(fā)現(xiàn)其實是有規(guī)則可循了。
下邊我給出來一段 “不那么完整的代碼案例” (關(guān)于這種營銷手段的設(shè)計核心在于思路,沒有完美的代碼,只有不斷精進(jìn)的設(shè)計)
這段代碼主要采用來策略模式的設(shè)計思路,不同的產(chǎn)品對應(yīng)不同的策略,產(chǎn)品和策略之間的關(guān)聯(lián)可以通過使用數(shù)據(jù)庫的方式來做綁定。
首先可以將每個服務(wù)項目看作是一條營銷的規(guī)則手段,因此我定義來一個marketing對象:
/***?營銷對象實體類**?@Author?idea*?@Date?created?in?9:39?上午?2020/5/4*/ @NoArgsConstructor @Data @Builder @AllArgsConstructor public?class?MarketingPO?{/***?主鍵id*/private?Integer?id;/***?營銷手段名稱?存儲class的名稱*/private?String?marketingName;/***?入?yún)?多個可以逗號分割*/private?String?inputVal;/***?描述*/private?String?des;/***?創(chuàng)建時間*/private?Date?createTime;/***?更新時間*/private?Date?updateTime;}接著便是產(chǎn)品和不同營銷手段之間做關(guān)聯(lián)
/***?通過產(chǎn)品id和營銷手段做關(guān)聯(lián)**?@Author?idea*?@Date?created?in?3:37?下午?2020/5/4*/ @Data @Builder @AllArgsConstructor @NoArgsConstructor public?class?MarketingProductPO?{/***?主鍵id*/private?Integer?id;/***?營銷工具id*/private?Integer?marketingId;/***?產(chǎn)品編號*/private?String?productNo;/***?描述*/private?String?des;/***?是否有效*/private?Integer?validStatus;/***?創(chuàng)建時間*/private?Date?createTime;/***?更新時間*/private?Date?updateTime; }接著是dao層的部分,不過這里我簡單化地將持久層邏輯寫在來代碼里面,只做參考:
/***?模擬dao層操作**?@Author?idea*?@Date?created?in?10:20?上午?2020/5/4*/ @Repository public?class?MarketingDao?implements?IMarketingDao?{private?static?List<MarketingPO>?MARKETING_LIST?=?new?ArrayList();static?{MarketingPO?disCountMarket?=?MarketingPO.builder().id(1).marketingName("com.sise.idea.present.impl.DiscountStrategy").des("折扣優(yōu)惠").inputVal("7").build();MarketingPO?redPacketMarket?=?MarketingPO.builder().id(2).marketingName("com.sise.idea.present.impl.RedPacketStrategy").des("紅包優(yōu)惠").inputVal("8").build();MarketingPO?newMemberCouponMarket?=?MarketingPO.builder().id(3).marketingName("com.sise.idea.present.impl.NewMemberCouponStrategy").des("新人優(yōu)惠券發(fā)送").inputVal("10").build();MARKETING_LIST.add(newMemberCouponMarket);MARKETING_LIST.add(disCountMarket);MARKETING_LIST.add(redPacketMarket);}@Overridepublic?List<MarketingPO>?selectMarketingByIds(List<Integer>?idList)?{List<MarketingPO>?marketingPOS?=?new?ArrayList<>(idList.size());for?(MarketingPO?marketingPO?:?MARKETING_LIST)?{if?(idList.contains(marketingPO.getId()))?{marketingPOS.add(marketingPO);}}return?marketingPOS;} }/***?@Author?idea*?@Date?created?in?3:45?下午?2020/5/4*/ @Repository public?class?MarketingProductDao?implements?IMarketingProductDao?{private?static?List<MarketingProductPO>?MARKET_PRODUCT_LIST?=?new?ArrayList<>();static?{MarketingProductPO?marketingProductPO?=?MarketingProductPO.builder().productNo("p111").marketingId(2).validStatus(1).des("2999套餐-發(fā)放優(yōu)惠券").build();MarketingProductPO?marketingProductPO2?=?MarketingProductPO.builder().productNo("p111").marketingId(3).validStatus(1).des("2999套餐-滿額紅包返現(xiàn)").build();MARKET_PRODUCT_LIST.add(marketingProductPO);MARKET_PRODUCT_LIST.add(marketingProductPO2);}@Overridepublic?List<MarketingProductPO>?selectByProductNo(String?productNo)?{List<MarketingProductPO>?marketingProductPOS?=?new?ArrayList<>();for?(MarketingProductPO?marketingProductPO?:?MARKET_PRODUCT_LIST)?{//產(chǎn)品編碼一致?而且規(guī)則有效if(marketingProductPO.getProductNo().equals(productNo)?&&?marketingProductPO.getValidStatus()==1){marketingProductPOS.add(marketingProductPO);}}return?marketingProductPOS;} }接著便是對所有的營銷手段都做了一層統(tǒng)一的封裝和抽象:
package?com.sise.策略模式.present;/***?關(guān)于營銷手段的策略**?@Author?idea*?@Date?created?in?9:20?上午?2020/5/4*/ public?interface?IMarketingStrategy?{/***?服務(wù)贈送的策略執(zhí)行**?@param?param?參數(shù)*?@return*/boolean?doMarketing(Object?...param); }接下來便是不同的營銷手段對應(yīng)不同的實現(xiàn),這里面我簡單做了一些實現(xiàn):
@Service public?class?RedPacketStrategy?implements?IMarketingStrategy?{@Overridepublic?boolean?doMarketing(Object...?param)?{System.out.println("紅包贈送策略");return?false;} }@Service public?class?DiscountStrategy?implements?IMarketingStrategy?{@Overridepublic?boolean?doMarketing(Object...?param)?{System.out.println("打折優(yōu)惠");return?false;} }@Service public?class?NewMemberCouponStrategy?implements?IMarketingStrategy?{@Overridepublic?boolean?doMarketing(Object...?param)?{System.out.println("新人贈送策略");return?false;} }@Service public?class?UpgradeStrategy?implements?IMarketingStrategy?{@Overridepublic?boolean?doMarketing(Object...?param)?{System.out.println("升級策略");return?false;} }既然有了不同營銷手段的具體實現(xiàn)方式,那么對于購買不同的產(chǎn)品也需要查詢到不同的營銷手段,這個時候就需要有一個轉(zhuǎn)換中間者的角色出現(xiàn)了:
/***?營銷工具核心執(zhí)行器**?@Author?idea*?@Date?created?in?9:34?上午?2020/5/4*/ public?interface?IMarketingCoreService?{/***?執(zhí)行不同的營銷工具**?@param?productNo?產(chǎn)品編碼*?@return*/boolean?doMarketingJob(String?productNo)?throws?Exception; }/***?營銷工具核心執(zhí)行器**?@Author?idea*?@Date?created?in?9:34?上午?2020/5/4*/ @Service public?class?MarketingCoreService?implements?IMarketingCoreService?{@Resourceprivate?IMarketingDao?iMarketingDao;@Resourceprivate?IMarketingProductDao?iMarketingProductDao;@Resourceprivate?ApplicationContext?applicationContext;@Overridepublic?boolean?doMarketingJob(String?productNo)?throws?ClassNotFoundException?{System.out.println("doMarketingJob?begin?=============");System.out.println(productNo);List<MarketingProductPO>?marketingProductPOS?=?iMarketingProductDao.selectByProductNo(productNo);if?(marketingProductPOS?!=?null)?{List<Integer>?marketingIdList?=?marketingProductPOS.stream().map(MarketingProductPO::getMarketingId).collect(Collectors.toList());List<MarketingPO>?marketingPOS?=?iMarketingDao.selectMarketingByIds(marketingIdList);for?(MarketingPO?marketingPO?:?marketingPOS)?{String?marketingName?=?marketingPO.getMarketingName();Class<?>?clazz?=?Class.forName(marketingName);IMarketingStrategy?marketingStrategy?=?(IMarketingStrategy)?applicationContext.getBean(clazz);marketingStrategy.doMarketing(marketingPO.getInputVal());}System.out.println("doMarketingJob?end?=============");return?true;}System.out.println("doMarketingJob?setting?is?empty?===========");return?false;} }具體的思路就和策略模式有點類似:
策略模式
模式定義:定義一系列算法,將每個算法都封裝起來,并且它們可以互換。策略模式是一種對象行為模式。
例如下圖:
最后為了方便測試,我在工程里面引入了spring-context的依賴:
測試的入口代碼:
/***?@Author?idea*?@Date?created?in?10:14?上午?2020/5/4*/ public?class?ApplicationDemo?{public?static?void?main(String[]?args)?throws?Exception?{AnnotationConfigApplicationContext?applicationContext?=?new?AnnotationConfigApplicationContext();applicationContext.scan("com.sise.idea.present");//啟動上下文applicationContext.refresh();IMarketingCoreService?marketingCoreService?=?applicationContext.getBean(MarketingCoreService.class);marketingCoreService.doMarketingJob("p111");} }最后根據(jù)規(guī)則,通過產(chǎn)品編碼來搜索到指定的營銷手段,并執(zhí)行對應(yīng)的程序邏輯:
設(shè)計不足點
文章上邊我曾經(jīng)提及過,沒有完美點代碼,只有隨著業(yè)務(wù)需求不斷變化的設(shè)計思路,因此在真正落地整套營銷系統(tǒng)的時候,還需要額外考慮很多的要素。例如說目前的這種設(shè)計只能滿足于針對單個產(chǎn)品層面,如果以后有出現(xiàn)針對完整訂單層面(例如說總支付訂單滿xxx元,享受xxx優(yōu)惠)的還需要額外去思考,加上不同的營銷手段之間是否有出現(xiàn)互斥的場景都是會有可能遇到的情況。
設(shè)計模式,是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性、程序的重用性。文中我并沒有過多地去講解什么是xx模式,但是當(dāng)通過某種較為靈活的方式來實現(xiàn)某樣功能時,可能就已經(jīng)使用了設(shè)計模式。
https://gitee.com/IdeaHome_admin/design_pattern/tree/master/design-model/src/main/java/com/sise/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/present
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的策略模式在公司项目中的运用实践,看完又可以涨一波实战经验了!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何抵御频发的 DDOS 攻击?
- 下一篇: NYOJ 594 还是A+B