如何在業(yè)務(wù)代碼中優(yōu)雅的使用策略模式

策略模式介紹

假設(shè)你正在開發(fā)一個電商平臺,其中涉及到商品的折扣策略。優(yōu)惠策略有很多種可能,如領(lǐng)取優(yōu)惠券抵扣、返現(xiàn)促銷、拼團(tuán)優(yōu)惠等。最初的實現(xiàn)可能會在購物車類中嵌入各種折扣邏輯,導(dǎo)致代碼的可維護(hù)性和擴(kuò)展性下降。

下面代碼在業(yè)務(wù)開發(fā)中經(jīng)常遇到,代碼滿足了業(yè)務(wù)需求,客戶可根據(jù)自己的需求選擇不同的優(yōu)惠策略。但是,經(jīng)過一段時間的業(yè)務(wù)積累,促銷活動會越來越多。于是,程序員就開始經(jīng)常加班,每次上活動之前都要通宵改代碼,而且要做重復(fù)測試,判斷邏輯可能也會變得越來越復(fù)雜。此時,我們要思考代碼是否需要重構(gòu)。

public?static?void?main(String[]?args)?{
????PromotionActivity?promotionActivity?=?null;

????String?promotionKey?=?"COUPON";

????if(StringUtils.equals(promotionKey,"COUPON")){
????????promotionActivity?=?new?PromotionActivity(new?CouponStrategy());
????}else?if(StringUtils.equals(promotionKey,"CASHBACK")){
????????promotionActivity?=?new?PromotionActivity(new?CashbackStrategy());
????}//......
????promotionActivity.execute();
}

下面我們看下策略模式如何優(yōu)雅的解決這個問題。

策略模式是一種行為型設(shè)計模式,它允許在運行時選擇算法的一種方式,使得算法可以獨立于客戶端代碼進(jìn)行變化。在業(yè)務(wù)代碼中使用策略模式可以幫助你實現(xiàn)可維護(hù)、可擴(kuò)展和可變化的代碼結(jié)構(gòu)。下面是在業(yè)務(wù)代碼中使用策略模式的一般步驟:

1.?定義策略接口:?首先,定義一個策略接口,其中聲明了策略的方法或行為。這些方法將在不同的具體策略類中實現(xiàn)。

2.?創(chuàng)建具體策略類:?創(chuàng)建實現(xiàn)策略接口的具體策略類,每個類實現(xiàn)了策略接口中的方法。每個具體策略類代表了一個算法或行為的具體實現(xiàn)。

3.?在客戶端代碼中使用策略:?在客戶端代碼中,通過持有策略接口類型的引用,可以在運行時選擇不同的策略實現(xiàn)。這樣客戶端代碼可以根據(jù)需要切換或替換不同的策略。

業(yè)務(wù)代碼中如何使用

現(xiàn)在后端項目基本都是基于?Spring Boot?開發(fā)的,我們基于?Spring Boot?作為基礎(chǔ)框架,教你如何使用?Spring?依賴注入的特性,優(yōu)雅的實現(xiàn)策略模式。

既然是策略模式,那么定義策略肯定是首當(dāng)其沖,策略我們使用枚舉實現(xiàn)最佳

public?enum?StrategyType?{

????STRATEGY_A(1,?"策略A"),

????STRATEGY_B(2,?"策略B");

????private?int?code;

????private?String?desc;

????StrategyType(int?code,?String?desc)?{
????????this.code?=?code;
????????this.desc?=?desc;
????}

????public?int?getCode()?{
????????return?code;
????}

????public?String?getDesc()?{
????????return?desc;
????}
}

再定義一個接口,接口有兩個方法,getType用來獲取策略的業(yè)務(wù)類型,execute用來執(zhí)行業(yè)務(wù)

public?interface?Strategy?{

????void?execute();

????StrategyType?getType();

}

這里我們實現(xiàn)個策略StrategyA

@Component("strategyA")
public?class?StrategyA?implements?Strategy?{

????@Override
????public?void?execute()?{
????????System.out.println("Executing?strategy?A");
????}


????@Override
????public?StrategyType?getType()?{
????????return?StrategyType.STRATEGY_A;
????}
}

再實現(xiàn)個策略StrategyB

@Component("strategyB")
public?class?StrategyB?implements?Strategy?{
????@Override
????public?void?execute()?{
????????System.out.println("Executing?strategy?B");
????}

????@Override
????public?StrategyType?getType()?{
????????return?StrategyType.STRATEGY_B;
????}

}

我們通過定義一個工廠類,然后使用?Spring?的依賴注入特性,可以注入一個接口的多個實現(xiàn),這里采用?List<Strategy>?的形式注入,Spring?也支持通過?Map<String,Strategy>?的形式注入,如果使用 Map 注入,那么 key 就是類名,小伙伴們自己也可以測試一下~

為方便調(diào)用我們需要將List<Strategy>轉(zhuǎn)換成Map<StrategyType, Strategy>結(jié)構(gòu),業(yè)務(wù)執(zhí)行時可以直接傳遞業(yè)務(wù)參數(shù)(這里是我們定義的一個業(yè)務(wù)枚舉StrategyType)獲取Bean。這里我們直接使用Spring@PostConstruct注解在方法上,表示此方法是在Spring實例化該Bean之后馬上執(zhí)行此方法。

@Service
public?class?StrategyFactory?{
????private?Map<StrategyType,?Strategy>?strategyMap?=?new?ConcurrentHashMap<>();

????@Resource
????private?List<Strategy>?strategyList;

????public?void?execute(StrategyType?type)?{
????????strategyMap.get(type).execute();
????}

????@PostConstruct
????public?void?init()?{

????????for?(Strategy?strategy?:?strategyList)?{
????????????strategyMap.put(strategy.getType(),?strategy);
????????}
????}
}

最后我們在業(yè)務(wù)類StrategyService直接使用就行了。

@Service
public?class?StrategyService?{

????@Resource
????private?StrategyFactory?strategyFactory;

????public?void?executeStrategy(StrategyType?type)?{
????????strategyFactory.execute(type);
????}
}

最終結(jié)構(gòu)如下所示:

總結(jié)

??使用 Spring 的依賴注入特性,可以注入一個接口的多個實現(xiàn),很容易就實現(xiàn)了策略模式的選擇,這樣后續(xù)添加一種策略的時候,完全不需要改動主要邏輯,只需添加具體實現(xiàn)即可。

??雖然我們是講策略模式,其實里面還包含了工廠模式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容