Go設計模式實戰--用模版和策略模式應對多渠道多場景支付和營銷
上一節給大家演示講解了訂單支付的業務流程中的各個步驟以及怎么在項目中進行微信支付的對接。不過現實的商品支付中一般會在收銀臺頁面讓用戶選擇以什么方式支付--是微信、支付寶或者是其他的什么支付、信用卡支付等等。
所以一般項目接入支付通道的時候不會只接入一種支付通道。這么干除了能避免依賴單一渠道的風險外,更多的還是因為互聯網公司常見的營銷玩法為了提高轉化率會高度依賴多渠道多場景支付,比如各種簽約支付、先用后付等等。
多場景支付的維護難度
隨著項目接入的支付渠道越來越多、支持的支付場景和營銷玩法越來越多,你的項目代碼該怎么開發呢?大多數情況下就是一個支付場景一個if 條件分支唄,甚至新接入的支付渠道也可以是一個大的 if 代碼分支、渠道的各種支付場景那就大分支里邊套小分支唄。
長此以往代碼的維護難度可想而之,到后期新加一個邏輯,為了保證上線不翻車,可能要把整個支付中的所有邏輯在測試階段都回歸一遍才敢上線。
那么有沒有什么辦法能讓這種代碼的發展別那么混亂,我希望給其中一個支付渠道的某類支付場景加了邏輯,測試時只回歸對應的場景即可,有什么好辦法嗎?
這就是本節要給大家介紹的兩個設計模式:模版模式和策略模式,我們通過把兩種設計模式結合起來的使用來解決這些問題。
大家看一些開源或者設計好的項目的代碼時會覺得好像它用了設計模式A,看了一會兒它咋又像設計模式B了,咋跟我學的設計模式的教程都不一樣?我想說的是,有這種感覺就對了,用設計模式解決實際問題,通常是多種設計模式綜合使用才能解決問題,單一設計模式能解決的問題還是太有限了。
設計思路
接下來我們進入正題,怎么使用模版模式和策略模式來設計項目,讓其以一個相對有序、可維護的發展趨勢來支撐多渠道多場景支付呢?
我們從兩個方面來思考這個問題:
- 這么多支付渠道,支付場景他們每次執行過程中有哪些共同點--即可提煉出來的標準化步驟?
- 找流程步驟中的可切步驟,有沒有可能這個步驟的實現方式從A切換到了B,代碼解決的流程就從A切換成了B?
如果你分析一通,發現沒有? 那不好意思,不是你分析的不對,就是這兩個模式確實用不上,那么咱就現有的代碼打打補丁,能用就行了,哈哈哈。
接下在咱再說一下為啥要兩種模式結合起來使用,其實很簡單,使用它們時的設計思路有以下幾點
- 模版限定流程的具體步驟(注:以下步驟請根據要實現的流程提煉出來,并不局限下面幾種)
- 校驗請求,檢查必要參數
- 防抖防重,避免重復請求
- 準備流程中的必要參數:對于支付來說有訂單數據、用戶數據等
- 發起流程的關鍵步驟:支付流程就是發起相應的支付方式
- 生成響應
- 策略決定應該怎么支付 (各種支付平臺的普通支付/簽約代扣/....),返回給客戶端什么樣的結果。
設計實現
說了這么多,我估計大家都有點懵了,沒辦法首先要給大家解釋清楚多支付渠道的多支付場景這個業務形態,其次應用上設計模式后代碼緯度都會讓整個代碼設計的理解難度會大幅增加。
針對咱們今天的流程場景,我畫了一個整個代碼設計的UML類圖:
圖片
首先我們定義接口 OrderPayTemplateContract,訂單支付的模版--對訂單支付執行過程的抽象, 模版方法中決定流程步驟的執行順序。
type OrderPayTemplateContract interface {
CreateOrderPay() (interface{}, error) // 模版方法
OrderPayHandlerContract
}
OrderPayTemplateContract 中的CreateOrderPay 方法為模版方法,即在它的內部決定各個步驟的執行順序,我們把流程步驟都放在了 OrderPayHandlerContract 接口中。
// OrderPayHandlerContract 訂單支付的處理器接口--對訂單支付各個主要步驟的抽象
type OrderPayHandlerContract interface {
// CheckRepetition 防重校驗
CheckRepetition() error
// ValidateOrder 檢驗Order參數是否符合預期
ValidateOrder() error
// LoadPayAndUserConfig 加載支付配置和支付平臺需要的一些用戶信息--比如微信的openID
LoadPayAndUserConfig() error
// LoadOrderPayStrategy 加載訂單支付策略
LoadOrderPayStrategy() error
// HandleOrderPay 發起支付
HandleOrderPay() (interface{}, error)
}
步驟中有一個加載訂單支付策略,我們定義了 OrderPayStrategyContract 支付策略接口,由其實現類去真正發起對支付平臺的調用。
type OrderPayStrategyContract interface {
// CreatePay 實現支付策略中有關創建支付的邏輯
// 可以根據策略本身決定去怎么實現 創建訂單|設置簽約碼|......
CreatePay(ctx context.Context, order *do.Order, payConfig *OrderPayConfig) (interface{}, error)
}