Spring?boot?運(yùn)用策略模式實(shí)現(xiàn)避免多次使用if
前言
這里就不詳細(xì)去介紹策略模式是怎么樣的了,想了解的可以點(diǎn)擊下面的鏈接
策略模式介紹的鏈接:Java 設(shè)計(jì)模式中的策略模式詳情
這里列出策略模式的好處
場(chǎng)景:某網(wǎng)頁(yè)有個(gè)支付,其中包含了微信、支付寶等方式的支付方式 ,后續(xù)明確還會(huì)進(jìn)行兼容其他的支付方式
用策略模式的好處:
- 避免多次使用if判斷具體是用哪種支付策略進(jìn)行操作。
- 因?yàn)槊糠N策略(微信支付、支付寶支付)的內(nèi)容都比較復(fù)雜。策略模式能將每種策略分離出來(lái),方面后續(xù)維護(hù)管理
下面我們將使用Spring boot 運(yùn)用策略模式,實(shí)現(xiàn)上面的需求
環(huán)境配置
- JDK8
- Spring boot 2.3.7.RELEASE
- 整合了spring-boot-starter-web
實(shí)現(xiàn)目標(biāo)
使用策略模式后,新加一種支付策略時(shí),只需要在策略枚舉中添加新加的策略信息,外加一個(gè)策略類即可,而不再需要添加新的if判斷。
準(zhǔn)備策略接口和具體實(shí)現(xiàn)策略類
支付策略接口
/** * 支付策略 */ public interface PayStrategy { /** * 支付(參數(shù)就沒(méi)具體寫(xiě)了,可以定義成每個(gè)支付必須要有的參數(shù)) * @return */ boolean pay(); }
微信支付策略類
/** * 第三方——微信支付(這里注意我修改了Bean的默認(rèn)命名) */ @Component("wechatPayStrategy") public class WeChatPayStrategyImpl implements PayStrategy{ /** * 支付 * @return */ @Override public boolean pay() { //進(jìn)行微信的支付邏輯 System.out.println("正在進(jìn)行微信的支付邏輯"); return true; } }
支付寶支付策略類
/** * 支付寶第三方支付(這里注意我修改了Bean的默認(rèn)命名) */ @Component("alipayStrategy") public class AliPayStrategyImpl implements PayStrategy { /** * 支付寶支付 * @return */ @Override public boolean pay() { //進(jìn)行支付寶支付邏輯 System.out.println("進(jìn)行支付寶支付邏輯"); return true; } }
上述已將各自的策略的處理類進(jìn)行了分離,接下來(lái)時(shí)使用支付策略工廠類和支付策略上下文將各自的策略類聯(lián)系起來(lái)
準(zhǔn)備支付策略上下文Context和支付策略工廠類
支付策略工廠類
package com.example.springboot_strategy.strategy.factory; import com.example.springboot_strategy.enums.PayStrategyEnum; import com.example.springboot_strategy.strategy.PayStrategy; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.swing.plaf.synth.SynthTextAreaUI; import java.util.Map; /** * 支付策略工廠類 */ @Component public class PayStrategyFactory { /** * 通過(guò)Spring容器的方式注入 */ @Resource private Map<String, PayStrategy> payStrategyMap; /** * 獲取對(duì)應(yīng)支付策略類 * @param payStrategyEnum 支付策略枚舉 */ public PayStrategy getPayStrategy(PayStrategyEnum payStrategyEnum){ if(!payStrategyMap.containsKey(payStrategyEnum.getClassName())){ System.out.println("沒(méi)有對(duì)應(yīng)的支付策略,無(wú)法進(jìn)行支付"); return null; } return payStrategyMap.get(payStrategyEnum.getClassName()); } }
這里工廠類的邏輯是利用了Spring容器的處理方式,如果有多種類同時(shí)實(shí)現(xiàn)了某個(gè)接口,那么可以使用Map集合接收,Map對(duì)應(yīng)的泛型,String是Bean名稱,PayStrategy是每個(gè)具體實(shí)現(xiàn)類,這樣我們就可以使用Bean類型去指定具體的策略類了,然后建立一個(gè)支付策略枚舉去管理這些Bean名稱。同時(shí),也可以將Bean名稱與客戶端定義的類型進(jìn)行關(guān)聯(lián)。
支付策略枚舉類
/** * 支付策略類型 */ public enum PayStrategyEnum { WECHAT_PAY("wechat","wechatPayStrategy","微信支付"), ALIPAY("alipay","alipayStrategy","支付寶支付") ; /** * 支付策略code */ private String code; /** * bean名稱 */ private String className; /** * 信息 */ private String info; PayStrategyEnum(String code,String className,String info){ this.code=code; this.className=className; this.info=info; } public String getCode() { return code; } public String getClassName() { return className; } public String getInfo() { return info; } }
上面枚舉類中code代表的是客戶端定義的類型(例如我從前端接收到的支付type,這個(gè)type可以是這個(gè)code),className顧名思義,指的是每種策略的bean名稱,info是代表每種策略的內(nèi)容
支付策略上下文
/** * 支付策略上下文 */ @Component public class PayStrategyContext { @Autowired private PayStrategyFactory payStrategyFactory; /** * 支付執(zhí)行 * @param payDTO 支付參數(shù) * @return */ public boolean payHandle(PayDTO payDTO){ //將某屬性的值轉(zhuǎn)換成具體的枚舉。這里是根據(jù)payDTO的type字段對(duì)應(yīng)枚舉的code進(jìn)行轉(zhuǎn)換 Optional<PayStrategyEnum> payStrategyEnumOptional = Arrays.stream(PayStrategyEnum.class.getEnumConstants()) .filter((e) -> e.getCode().equals(payDTO.getType())).findAny(); if(!payStrategyEnumOptional.isPresent()){ System.out.println("匹配不到具體支付策略"); return false; } PayStrategyEnum payStrategyEnum = payStrategyEnumOptional.get(); PayStrategy payStrategy = payStrategyFactory.getPayStrategy(payStrategyEnum); //進(jìn)行payDto參數(shù)的處理..... boolean pay = payStrategy.pay(); //支付后的記錄處理.. return true; } }
pageDto類
/** * 支付DTO */ public class PayDTO { /** * 支付類型 */ private String type; /** * 支付金額 */ private BigDecimal payMoney; /** * ........... */ public String getType() { return type; } public void setType(String type) { this.type = type; } public BigDecimal getPayMoney() { return payMoney; } public void setPayMoney(BigDecimal payMoney) { this.payMoney = payMoney; } }
這個(gè)策略上下文,則是選擇策略的入口,這里會(huì)進(jìn)行參數(shù)的處理,將這里我就將pageDTO類中的type字符串轉(zhuǎn)換成對(duì)應(yīng)的枚舉類。
到這里使用策略模式的編寫(xiě)算是完成了,下面進(jìn)行編寫(xiě)客戶端的代碼
客戶端代碼
支付控制器
@RestController @RequestMapping("pay") public class PayController { @Autowired private PayStrategyContext payStrategyContext; @PostMapping public boolean pay(@RequestBody PayDTO payDTO){ //這里因?yàn)閼小?。就沒(méi)有加上Service層了,直接在控制器處理 return payStrategyContext.payHandle(payDTO); } }
效果
新需求
后續(xù)新增一個(gè)銀聯(lián)的支付方式,我們只需要添加銀聯(lián)的支付策略類和添加銀聯(lián)的支付枚舉即可實(shí)現(xiàn)
添加銀聯(lián)的支付策略類
/** * 銀聯(lián)支付(這里注意我修改了Bean的默認(rèn)命名) */ @Component("unionPayStrategy") public class UnionPayStrategyImp implements PayStrategy { /** * 銀聯(lián)支付 * @return */ @Override public boolean pay() { //進(jìn)行銀聯(lián)的支付 System.out.println("進(jìn)行銀聯(lián)的支付邏輯"); return true; } }
在枚舉類中添加銀聯(lián)的支付枚舉
/** * 支付策略類型 */ public enum PayStrategyEnum { WECHAT_PAY("wechat","wechatPayStrategy","微信支付"), ALIPAY("alipay","alipayStrategy","支付寶支付"), UNION_PAY("unionpay","unionPayStrategy","銀聯(lián)支付") ; /** * 支付策略code */ private String code; /** * bean名稱 */ private String className; /** * 信息 */ private String info; PayStrategyEnum(String code,String className,String info){ this.code=code; this.className=className; this.info=info; } public String getCode() { return code; } public String getClassName() { return className; } public String getInfo() { return info; } } 復(fù)制代碼
實(shí)現(xiàn)效果
到此這篇關(guān)于Spring boot 運(yùn)用策略模式實(shí)現(xiàn)避免多次使用if的文章就介紹到這了,更多相關(guān)Spring boot 避免多次使用if內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot?pom文件加入監(jiān)控依賴后沒(méi)有起作用的解決
這篇文章主要介紹了springboot?pom文件加入監(jiān)控依賴后沒(méi)有起作用的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02關(guān)于Redis鍵值出現(xiàn)\xac\xed\x00\x05t\x00&錯(cuò)誤的解決方法
這篇文章主要介紹了關(guān)于Redis鍵值出現(xiàn)\xac\xed\x00\x05t\x00&的解決方法,出現(xiàn)該問(wèn)題的原因是, redis template向redis存放使用java對(duì)象序列化的值,序列化方式和string的一般方式不同,需要的朋友可以參考下2023-08-08Java的MyBatis框架中實(shí)現(xiàn)多表連接查詢和查詢結(jié)果分頁(yè)
這篇文章主要介紹了Java的MyBatis框架中實(shí)現(xiàn)多表連接查詢和查詢結(jié)果分頁(yè),借助MyBatis框架中帶有的動(dòng)態(tài)SQL查詢功能可以比普通SQL查詢做到更多,需要的朋友可以參考下2016-04-04java集合 collection-list-LinkedList詳解
下面小編就為大家?guī)?lái)一篇java集合 collection-list-LinkedList詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01Springboot啟動(dòng)不檢查JPA的數(shù)據(jù)源配置方式
這篇文章主要介紹了Springboot啟動(dòng)不檢查JPA的數(shù)據(jù)源配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08智能 AI 代碼生成工具 Cursor 安裝和使用超詳細(xì)教程
Cursor.so 是一個(gè)集成了 GPT-4 的國(guó)內(nèi)直接可以訪問(wèn)的,優(yōu)秀而強(qiáng)大的免費(fèi)代碼生成器,可以幫助你快速編寫(xiě)、編輯和討論代碼,這篇文章主要介紹了智能 AI 代碼生成工具 Cursor 安裝和使用介紹,需要的朋友可以參考下2023-05-05解析Java的Spring框架的BeanPostProcessor發(fā)布處理器
這篇文章主要介紹了Java的Spring框架的BeanPostProcessor發(fā)布處理器,Spring是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下2015-12-12java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別
這篇文章主要介紹了java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別的相關(guān)資料,本文主要說(shuō)明兩者的區(qū)別以防大家混淆概念,需要的朋友可以參考下2017-08-08