Go 程序里 if else 分支太多?試著用策略模式治理一下吧!
大家好,我是每周在這里陪你一起進(jìn)步的網(wǎng)管。
上篇文章我給大家分享了設(shè)計(jì)模式中的模版模式,給大家講了用模版模式在項(xiàng)目開(kāi)發(fā)時(shí)提煉流程、減少重復(fù)開(kāi)發(fā)的技巧。同時(shí),在上一篇文章我也分享了我總結(jié)的一個(gè)暴論,那就是“模板、策略和職責(zé)鏈三個(gè)設(shè)計(jì)模式是解決業(yè)務(wù)系統(tǒng)流程復(fù)雜多變這個(gè)痛點(diǎn)的利器”。
今天我們繼續(xù)接著一起學(xué)習(xí)一下策略模式,以及用 Go 代碼怎么實(shí)現(xiàn)策略模式。
什么是策略模式
策略模式是一種行為設(shè)計(jì)模式,通過(guò)策略模式,可以在運(yùn)行時(shí)修改一個(gè)對(duì)象的行為。很多資料里對(duì)它的定義是:
定義一類(lèi)算法族,將每個(gè)算法分別封裝起來(lái),讓他們可以互相替換,此模式讓算法的變化獨(dú)立于使用算法的客戶端。
看完策略模式這個(gè)定義,你是不是也有一種看了等于沒(méi)看的感覺(jué),我一開(kāi)始看的時(shí)候也是這樣,下面我再用一些大白話給大家解釋一下。
白話策略模式
策略模式這個(gè)定義乍一看起來(lái),還是挺抽象、挺難懂的,這里說(shuō)的算法并不是我們想找工作準(zhǔn)備面試時(shí)每天要刷的那種算法;定義一類(lèi)算法族中的算法族說(shuō)的要完成的某項(xiàng)任務(wù)的歸類(lèi),舉個(gè)例子來(lái)說(shuō)比如用戶支付,就是個(gè)任務(wù)類(lèi)。
算法族中的每個(gè)算法(即策略)則是說(shuō)的完成這項(xiàng)任務(wù)的具體方式,結(jié)合我們的例子來(lái)說(shuō)就是可以用支付寶也可以用微信支付這兩種方式 (算法) ,來(lái)完成我們定義的用戶支付這項(xiàng)任務(wù) (算法族)。
策略模式主要用于允許我們的程序在運(yùn)行時(shí)動(dòng)態(tài)更改一個(gè)任務(wù)的處理邏輯,常見(jiàn)的應(yīng)用場(chǎng)景有針對(duì)軟件用戶群體的不同策略切換(用一個(gè)爛大街的詞兒表達(dá)就是千人千面)和業(yè)務(wù)流程兜底切換。
注意:這里是為了大家好理解舉了支付這個(gè)例子,實(shí)際上運(yùn)行時(shí)切換支付方式還是挺復(fù)雜的,實(shí)踐的時(shí)候你可以先從運(yùn)行時(shí)切換通知用戶的任務(wù)練起。
策略模式要解決的問(wèn)題是,讓使用客戶端跟具體執(zhí)行任務(wù)的策略解耦,不管使用哪種策略完成任務(wù),不需要更改客戶端使用策略的方式。
上面說(shuō)的這些使用策略模式完成任務(wù)的整個(gè)形態(tài)用 UML 圖表示出來(lái),會(huì)比較清晰,策略模式的 UML 圖如下:
圖中,主要有四類(lèi)角色:
客戶端:這個(gè)客戶端可以簡(jiǎn)單理解成是發(fā)起任務(wù)調(diào)用的代碼。
抽象策略:就是上面定義中的算法族,是所有具體策略的通用接口,聲明了用于執(zhí)行完成任務(wù)的方法。
具體策略:實(shí)現(xiàn)了抽象策略,定義了具體應(yīng)該怎么完成任務(wù)。
- 上下文:作為客戶端和具體策略的中間層,達(dá)到客戶端與具體策略解耦的效果,它維護(hù)指向具體策略的引用,且僅通過(guò)抽象策略中定義的接口與具體策略進(jìn)行交流。常用的實(shí)現(xiàn)方式是通過(guò)組合
上面類(lèi)圖里一個(gè)細(xì)節(jié),上下文對(duì)象引用具體策略類(lèi)的時(shí)候,使用的是組合的方式,讓其私有屬性指向策略接口的具體實(shí)現(xiàn),這樣就能完成在運(yùn)行時(shí)修改執(zhí)行任務(wù)的具體策略的效果(通過(guò)SetStrategy方法)。
光看上面的描述和UML圖,還是有點(diǎn)單薄,為了更容易理解,下面咱們?cè)倥e個(gè)更具體點(diǎn)的例子。
策略模式示例--實(shí)現(xiàn)支付策略
舉例環(huán)節(jié),接著用我們上面用的用戶支付這個(gè)任務(wù)為例子。比如說(shuō)在購(gòu)物 App 上買(mǎi)東西后要付錢(qián),客戶端使用微信支付、或者是其他三方在線支付。如果使用策略模式進(jìn)行解耦,客戶端都可以使用同樣的調(diào)用方式完成支付,甚至可以在微信支付不能使用時(shí),讓?xiě)?yīng)用無(wú)痛地切換到三方支付,來(lái)完成支付。
注意這里的客戶端是上面說(shuō)的,調(diào)用上下文的代碼,不是手機(jī)APP。
在用代碼實(shí)現(xiàn)支付策略前,先用 UML 類(lèi)圖梳理一下整個(gè)實(shí)現(xiàn)的大體結(jié)構(gòu):
PayBehavior:抽象策略,對(duì)支付任務(wù)進(jìn)行接口抽象
WxPay 和 ThirdPay :是具體的策略實(shí)現(xiàn)
PaxCtx:上下文對(duì)象在這里有兩個(gè)作用,第一是協(xié)調(diào)自己持有的 PayBehavior 具體實(shí)現(xiàn),完成支付的任務(wù),第二是維護(hù)發(fā)起支付需要的支付參數(shù)--即圖中的私有屬性payParams。
下面我們把這個(gè) UML 圖轉(zhuǎn)化為代碼實(shí)現(xiàn),首先是定義PayBehavior 策略的接口
有了接口后,我們來(lái)定義兩個(gè)策略的實(shí)現(xiàn)
有了策略的實(shí)現(xiàn)后,還得有個(gè)上下文來(lái)協(xié)調(diào)它們,以及持有完成這個(gè)任務(wù)所必需的那些入?yún)ayParams
所有這些代碼都準(zhǔn)備好后,我們就可以試著運(yùn)行程序調(diào)用它們了。
這個(gè)例子的實(shí)現(xiàn)還是比較簡(jiǎn)單的,相信大家都能看懂,我覺(jué)得最重要的是理解這個(gè)代碼框架,后面自己結(jié)合實(shí)際在項(xiàng)目里實(shí)現(xiàn)策略模式的時(shí)候,可以支持拿來(lái)套用。
本文的完整源碼,已經(jīng)同步收錄到我整理的電子教程里啦,可向我的公眾號(hào)「網(wǎng)管叨bi叨」發(fā)送關(guān)鍵字【設(shè)計(jì)模式】領(lǐng)取。
下面我們?cè)賮?lái)說(shuō)說(shuō)策略模式和上篇文章學(xué)習(xí)的模板模式的區(qū)別和關(guān)聯(lián)使用。
策略模式和模板模式
策略模式和模版模式經(jīng)常配合使用,策略模式是讓完成某個(gè)任務(wù)的具體方式可以相互切換,而模版模式則是針對(duì)一個(gè)流程的共性梳理出固定的執(zhí)行步驟,具體步驟的執(zhí)行方式下放給子類(lèi)來(lái)實(shí)現(xiàn)。兩者解耦的維度不一樣,策略模式在抽象方法的實(shí)現(xiàn)里,經(jīng)常會(huì)用到模板模式。
還是拿我們上面的支付行為舉例子。上面策略模式定義了一個(gè)算法族(支付),以及多個(gè)具體算法實(shí)現(xiàn)(微信、三方支付),讓支付策略對(duì)客戶端解耦。
上面咱們的示例代碼還是比較簡(jiǎn)單的,通常完成支付時(shí),還需要用參數(shù)生成簽名、驗(yàn)證客戶端傳過(guò)來(lái)的簽名、調(diào)用支付基礎(chǔ)服務(wù)進(jìn)行預(yù)下單、下單等操作,但是每種支付基礎(chǔ)服務(wù)設(shè)計(jì)的接口和交互流程可能會(huì)有些小的差別,這個(gè)時(shí)候就可以用上簽名學(xué)的模版模式,統(tǒng)一支付任務(wù)內(nèi)部的流程步驟,策略模式、模版模式相結(jié)合使用能讓我們寫(xiě)的程序更健壯、更容易維護(hù)。