詳解Java如何在業(yè)務(wù)代碼中優(yōu)雅的使用策略模式
策略模式介紹
假設(shè)你正在開(kāi)發(fā)一個(gè)電商平臺(tái),其中涉及到商品的折扣策略。優(yōu)惠策略有很多種可能,如領(lǐng)取優(yōu)惠券抵扣、返現(xiàn)促銷(xiāo)、拼團(tuán)優(yōu)惠等。最初的實(shí)現(xiàn)可能會(huì)在購(gòu)物車(chē)類(lèi)中嵌入各種折扣邏輯,導(dǎo)致代碼的可維護(hù)性和擴(kuò)展性下降。
下面代碼在業(yè)務(wù)開(kāi)發(fā)中經(jīng)常遇到,代碼滿足了業(yè)務(wù)需求,客戶(hù)可根據(jù)自己的需求選擇不同的優(yōu)惠策略。但是,經(jīng)過(guò)一段時(shí)間的業(yè)務(wù)積累,促銷(xiāo)活動(dòng)會(huì)越來(lái)越多。于是,程序員就開(kāi)始經(jīng)常加班,每次上活動(dòng)之前都要通宵改代碼,而且要做重復(fù)測(cè)試,判斷邏輯可能也會(huì)變得越來(lái)越復(fù)雜。此時(shí),我們要思考代碼是否需要重構(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)雅的解決這個(gè)問(wèn)題。
策略模式是一種行為型設(shè)計(jì)模式,它允許在運(yùn)行時(shí)選擇算法的一種方式,使得算法可以獨(dú)立于客戶(hù)端代碼進(jìn)行變化。在業(yè)務(wù)代碼中使用策略模式可以幫助你實(shí)現(xiàn)可維護(hù)、可擴(kuò)展和可變化的代碼結(jié)構(gòu)。下面是在業(yè)務(wù)代碼中使用策略模式的一般步驟:
- 定義策略接口: 首先,定義一個(gè)策略接口,其中聲明了策略的方法或行為。這些方法將在不同的具體策略類(lèi)中實(shí)現(xiàn)。
- 創(chuàng)建具體策略類(lèi): 創(chuàng)建實(shí)現(xiàn)策略接口的具體策略類(lèi),每個(gè)類(lèi)實(shí)現(xiàn)了策略接口中的方法。每個(gè)具體策略類(lèi)代表了一個(gè)算法或行為的具體實(shí)現(xiàn)。
- 在客戶(hù)端代碼中使用策略: 在客戶(hù)端代碼中,通過(guò)持有策略接口類(lèi)型的引用,可以在運(yùn)行時(shí)選擇不同的策略實(shí)現(xiàn)。這樣客戶(hù)端代碼可以根據(jù)需要切換或替換不同的策略。
業(yè)務(wù)代碼中如何使用
現(xiàn)在后端項(xiàng)目基本都是基于 Spring Boot
開(kāi)發(fā)的,我們基于 Spring Boot
作為基礎(chǔ)框架,教你如何使用 Spring
依賴(lài)注入的特性,優(yōu)雅的實(shí)現(xiàn)策略模式。
既然是策略模式,那么定義策略肯定是首當(dāng)其沖,策略我們使用枚舉實(shí)現(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; ? ? } }
再定義一個(gè)接口,接口有兩個(gè)方法,getType
用來(lái)獲取策略的業(yè)務(wù)類(lèi)型,execute
用來(lái)執(zhí)行業(yè)務(wù)
public interface Strategy { ? ? void execute(); ? ? StrategyType getType(); }
這里我們實(shí)現(xiàn)個(gè)策略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; ? ? } }
再實(shí)現(xiàn)個(gè)策略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; ? ? } }
我們通過(guò)定義一個(gè)工廠類(lèi),然后使用 Spring
的依賴(lài)注入特性,可以注入一個(gè)接口的多個(gè)實(shí)現(xiàn),這里采用 List<Strategy>
的形式注入,Spring
也支持通過(guò) Map<String,Strategy>
的形式注入,如果使用 Map 注入,那么 key 就是類(lèi)名,小伙伴們自己也可以測(cè)試一下~
為方便調(diào)用我們需要將List<Strategy>
轉(zhuǎn)換成Map<StrategyType, Strategy>
結(jié)構(gòu),業(yè)務(wù)執(zhí)行時(shí)可以直接傳遞業(yè)務(wù)參數(shù)(這里是我們定義的一個(gè)業(yè)務(wù)枚舉StrategyType
)獲取Bean。這里我們直接使用Spring
的@PostConstruct
注解在方法上,表示此方法是在Spring
實(shí)例化該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); ? ? ? ? } ? ? } }
最后我們?cè)跇I(yè)務(wù)類(lèi)StrategyService
直接使用就行了。
@Service public class StrategyService { ? ? @Resource ? ? private StrategyFactory strategyFactory; ? ? public void executeStrategy(StrategyType type) { ? ? ? ? strategyFactory.execute(type); ? ? } }
最終結(jié)構(gòu)如下所示:
總結(jié)
使用 Spring 的依賴(lài)注入特性,可以注入一個(gè)接口的多個(gè)實(shí)現(xiàn),很容易就實(shí)現(xiàn)了策略模式的選擇,這樣后續(xù)添加一種策略的時(shí)候,完全不需要改動(dòng)主要邏輯,只需添加具體實(shí)現(xiàn)即可。
雖然我們是講策略模式,其實(shí)里面還包含了工廠模式。
到此這篇關(guān)于詳解Java如何在業(yè)務(wù)代碼中優(yōu)雅的使用策略模式的文章就介紹到這了,更多相關(guān)Java策略模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis之類(lèi)型處理器TypeHandler的作用與自定義方式
這篇文章主要介紹了Mybatis之類(lèi)型處理器TypeHandler的作用與自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04關(guān)于springboot中對(duì)sqlSessionFactoryBean的自定義
這篇文章主要介紹了springboot中對(duì)sqlSessionFactoryBean的自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot多環(huán)境配置及配置文件分類(lèi)實(shí)例詳解
這篇文章主要介紹了SpringBoot多環(huán)境配置及配置文件分類(lèi),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10SpringMVC 上傳文件 MultipartFile 轉(zhuǎn)為 File的方法
這篇文章主要介紹了SpringMVC 上傳文件 MultipartFile 轉(zhuǎn)為 File的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02IDEA導(dǎo)入eclipse項(xiàng)目并且部署到tomcat的步驟詳解
這篇文章主要給大家介紹了關(guān)于IDEA導(dǎo)入eclipse項(xiàng)目并且部署到tomcat的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02使用mybatis框架連接mysql數(shù)據(jù)庫(kù)的超詳細(xì)步驟
MyBatis是目前java項(xiàng)目連接數(shù)據(jù)庫(kù)的最流行的orm框架了,下面這篇文章主要給大家介紹了關(guān)于使用mybatis框架連接mysql數(shù)據(jù)庫(kù)的超詳細(xì)步驟,文中通過(guò)實(shí)例代碼和圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04Spring核心思想之淺談IoC容器與依賴(lài)倒置(DI)
文章介紹了Spring的IoC和DI機(jī)制,以及MyBatis的動(dòng)態(tài)代理,通過(guò)注解和反射,Spring能夠自動(dòng)管理對(duì)象的創(chuàng)建和依賴(lài)注入,而MyBatis則通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)了接口方法到數(shù)據(jù)庫(kù)操作的映射,文章詳細(xì)解釋了Spring和MyBatis的工作原理,并通過(guò)示例代碼展示了它們的結(jié)合使用方式2025-01-01Java日期時(shí)間處理問(wèn)題(從Date、Calendar到SimpleDateFormat)
這篇文章主要介紹了Java日期時(shí)間處理深度解析(從Date、Calendar到SimpleDateFormat),我們?cè)敿?xì)討論了Java中的日期和時(shí)間處理,包括Date、Calendar和SimpleDateFormat類(lèi)的使用,以及Java?8引入的新的日期時(shí)間API的優(yōu)勢(shì),需要的朋友可以參考下2024-08-08