設計模式 —— 模板方法模式

簡介

模板方法模式(Template Method Pattern)定義一個操做中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。java

模板方法模式是結構最簡單的行爲型設計模式,在其結構中只存在父類與子類之間的繼承關係。經過使用模板方法模式,能夠將一些複雜流程的實現步驟封裝在一系列基本方法中,在抽象父類中提供一個稱之爲模板方法的方法來定義這些基本方法的執行次序,而經過其子類來覆蓋某些步驟,從而使得相同的算法框架能夠有不一樣的執行結果。算法

模板方法中的方法能夠分爲兩大類:模板方法和基本方法。設計模式

模板方法

一個模板方法是定義在抽象類中的,把基本操做方法組合在一塊兒造成一個總算法或一個總行爲的方法。 一個抽象類能夠有任意多個模板方法,而不限於一個。每個模板方法均可以調用任意多個具體方法。服務器

基本方法

基本方法又能夠分爲三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。微信

  1. 抽象方法:一個抽象方法由抽象類聲明,由具體子類實現。在Java語言裏抽象方法以abstract關鍵字標示;
  2. 具體方法:一個具體方法由抽象類聲明並實現,而子類並不實現或置換;
  3. 鉤子方法:一個鉤子方法由抽象類聲明並實現,而子類會加以擴展。一般抽象類給出的實現是一個空實現,做爲方法的默認實現。

實例

對接過第三方支付的小夥伴都知道,在接入第三方支付時,通常支付結果都會經過異步回調的形式,通知商戶服務器。而咱們獲得這些數據時通常都是同一流程的處理方式:驗籤 — 更新訂單狀態 — 給第三方支付服務器響應。 下面以支付寶和微信爲例:支付寶和微信的驗籤方式和響應結果方式都是不同的, 而更新訂單狀態都是商戶這邊處理因此業務邏輯是同樣的。框架

抽象模板類:異步

public abstract class AbstractPayNotifyTemplate {

    /** * 支付異步回調處理 * * @param params 回調參數 */
    public void onNotify(Map<String, String> params) {
        //驗證簽名
        final boolean sign = verifySign(params);
        if (sign) {
            // 給第三方支付服務器回覆支付失敗狀態
            setResponse(PayStatus.ERROR);
            return;
        }
        //從參數獲取訂單編號並更新訂單支付狀態,爲支付成功
        final String orderSn = params.get("out_trade_no");
        updateOrderPayStatusSuccess(orderSn);
        // 給第三方支付服務器回覆支付成功狀態
        setResponse(PayStatus.SUCCESS);
    }

    /** * 驗籤 * * @param params 回調參數 * @return 驗簽結果 */
    protected abstract boolean verifySign(Map<String, String> params);

    /** * 更新訂單支付狀態爲支付成功 * * @param orderSn 訂單編號 */
    private void updateOrderPayStatusSuccess(String orderSn) {
        // 根據訂單編號更新訂單支付狀態爲支付成功
    }

    /** * 給第三方支付返回 * * @param status 支付狀態 */
    protected abstract void setResponse(PayStatus status);
}
複製代碼

具體模板類:ide

// 支付寶支付回調類
public class AliPayNotifyTemplate extends AbstractPayNotifyTemplate {

    @Override
    protected boolean verifySign(Map<String, String> params) {
        // 調用支付寶驗籤接口, 並返回驗簽結果
        return true;
    }

    @Override
    protected void setResponse(PayStatus status) {
        String res = Objects.equals(PayStatus.SUCCESS, status) ? "success" : "error";

        // 調用 ResponseUtils 直接返回 res 字符串
    }
}

// 微信支付回調類
public class WxPayNotifyTemplate extends AbstractPayNotifyTemplate {

    @Override
    protected boolean verifySign(Map<String, String> params) {
        // 調用微信支付驗籤接口, 並返回驗簽結果
        return true;
    }

    @Override
    protected void setResponse(PayStatus status) {
        String returnCode = "FAIL";
        String returnMsg = "";
        if (Objects.equals(PayStatus.SUCCESS, status)) {
            returnCode = "SUCCESS";
            returnMsg = "OK";
        }
        String res = String.format("<xml><return_code><![CDATA[%s]]></return_code><return_msg><![CDATA[%s]]></return_msg></xml>", returnCode, returnMsg);

        // 調用 ResponseUtils 返回 res xml格式內容
    }
}
複製代碼

固然這只是簡單例子,幫助理解模板方法模式。實際項目中還帶有各類參數、異常的處理、工具類的封裝,以及其餘設計模式的應用。工具

優勢

  1. 提升代碼複用性。將相同部分的代碼放在抽象的父類中;微信支付

  2. 提升了拓展性。將不一樣的代碼放入不一樣的子類中,經過對子類的擴展增長新的行爲;

  3. 可實現一種反向控制結構,經過子類覆蓋父類的鉤子方法來決定某一特定步驟是否須要執行。(此處實例沒有體現)

缺點

引入了抽象類,每個不一樣的實現都須要一個子類來實現,致使類的個數增長,從而增長了系統實現的複雜度。

適用場景

  1. 對一些複雜的算法進行分割,將其算法中固定不變的部分設計爲模板方法和父類具體方法,而一些能夠改變的細節由其子類來實現;
  2. 各子類中公共的行爲應被提取出來並集中到一個公共父類中以免代碼重複;
  3. 須要經過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。
相關文章
相關標籤/搜索