從聚合支付業務的設計來聊聊策略模式

碼農小胖哥發表於2020-06-03

六月福利

2020年6月公眾號碼農小胖哥原創文章轉發第一名將送全新《Spring Boot實戰》實體書一本,該書是學習熱門框架 Spring Boot的經典之作。你不再需要依靠運氣,而是勤奮。截止統計日期2020年6月30日,統計資料以官方公眾號工具為準,運營人員不參加活動,本次活動圖書由掘金社群贊助。

1. 前言

前幾天講了設計模式中的命令模式,今天來看看另一個模式。移動支付目前在國內已經是非常普及了,連樓下早餐攤的七十多歲大媽也使用支付寶和微信支付賣雞蛋餅。如果讓你做一個App你肯定要考慮多個渠道支付,以保證獲客渠道。如果讓你來接入多種支付渠道你會怎麼設計?

2. 通常寫法

一般下面這種寫法很容易被創造出來:

    public boolean pay(BigDecimal amount){
        
        boolean ret =false;
        if (alipay){
            //todo 支付寶的邏輯
        }else if (wechatpay){
            //todo 微信支付的邏輯
        }else if (ooxx){
           // …… 
        }
        return ret;
    }

如果整合了四五種支付,這個程式碼就沒法看了少說幾千行,而且改動某個支付的邏輯很容易改了其它支付的邏輯。因此需要合理的設計來避免這種風險。

3. 策略模式

大部分的支付可以簡化為這個流程:

中間的發起支付前邏輯支付後處理邏輯是客戶端的自定義業務邏輯,向支付伺服器傳送的請求只會攜帶對應支付伺服器特定要求的引數呼叫不同的支付SDK。所以我們分別建立對應支付方式的策略來隔離區分它們,降低它們的耦合度。當準備支付時我們只需要選擇對應的策略就可以了。

這就用到了設計模式中的策略模式:

結合上面的類圖,我們就來結合著需求來聊聊策略模式中的主要幾個角色。

  • Strategy介面。這個介面用來宣告每一種方式的獨立執行策略,用來封裝具體策略的特有演算法邏輯。
  • ConcreteStrategyStrategy的實現類。實現了不同策略的演算法邏輯。比如每種支付的呼叫細節等等。
  • Context上下文。它通過策略介面來引用了具體的策略並使用具體的策略來執行邏輯,同時所有策略的共性也可以在該類中進行統一處理。在聚合支付需求中我們傳入一個策略,先執行支付前的邏輯,然後使用策略,策略執行完畢後,再執行後置的共性邏輯。
  • Client客戶端。建立策略物件並傳遞給上下文Context,然後由上下文執行具體的策略。

結合業務邏輯是這樣的:請求到達客戶端,客戶端根據請求中包含的支付渠道來構建對應的策略物件並把它交給上下文物件去執行支付流程。

然後我們就可以分別為支付寶、微信支付、銀聯支付構造三個策略物件 AliPayStrategyWechatPayStrategyUnionPayStrategy ,我們來模擬一下執行策略:

public class Client {

    public static void main(String[] args) {
        // 獲取請求中的支付渠道標識
        String code = "p01";
        PayStrategy payStrategy = null;
        PayRequest request = null;
        
        if (PayType.ALI.getCode().equals(code)) {
            //組裝為支付寶支付策略
            payStrategy = new AliPayStrategy();
            // 構造支付寶請求引數
            request = new AliPayRequest();
        }
        if (PayType.WECHAT.getCode().equals(code)) {
            //組裝為微信支付策略
            payStrategy = new AliPayStrategy();
            // 構造微信支付請求引數
            request = new WechatPayRequest();
        }

        if (PayType.UNION.getCode().equals(code)) {
            //組裝為銀聯支付策略
            payStrategy = new UnionPayStrategy();
            // 構造銀聯支付請求引數
            request = new UnionPayRequest();
        }

        if (Objects.nonNull(payStrategy)) {
            PayContext payContext = new PayContext();
            payContext.setPayStrategy(payStrategy);
            payContext.pay(request);
        }
    }
}

我們拿到請求中的支付標識,然後初始化對應的支付策略,封裝指定的請求引數,交給上下文物件PayContext 來執行請求。如果你再增加什麼ApplePay之類的去實現ApplePayStrategy就行了。

4. 優缺點

策略模式並不都帶來正面的作用。

4.1 優點

  • 我們將演算法的實現和演算法的使用進行了隔離,演算法實現只關心演算法邏輯,使用演算法只關心什麼條件下使用什麼演算法。
  • 開閉原則,無需修改上下文物件,想擴充套件只需要引入新的策略。
  • 執行時根據條件動態的去切換演算法。
  • 適應個性的同時也可以相容共性。

4.2 缺點

  • 客戶端必須明確知道啟用策略的條件。
  • 引入太多的策略類。
  • 可被一些函式式介面所代替。虛擬碼Pay.request(data).strategy(data->{ })

5. 總結

策略模式也是很常見而且有著廣泛使用場景的設計模式。今天我們從聚合支付來學習了策略模式,對它的優缺點也進行了一個分析。隨著函數語言程式設計的普及,策略模式開始被逐漸的代替,但是它依然值得我們去學習。感謝你的閱讀,多多關注:碼農小胖哥,更多程式設計乾貨奉上。

關注公眾號:Felordcn 獲取更多資訊

個人部落格:https://felord.cn

相關文章