源碼中的設計模式--模板方法模式(鉤子方法)

  在上次《源碼中的設計模式--模板方法模式》中分享了有關模板方法設計模式方面的東西,不知道還有印象沒,重溫下其釋義,

模板方法模式在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重寫定義算法中的某些步驟。

  在上次中舉了這樣的場景,要調用系統A、系統B接口,把兩個系統的數據讀取過來,保存在我們自己的數據庫中,其實現的UML圖如下,

  現在突然,系統A的對接人說,在調用他的接口前需要進行校驗,驗證身份,纔可以進行調用。看看上面的UML圖我們要怎麼修改代碼,我們把之前的場景抽象了四步:組裝參數、發送請求、處理返回參數、保存數據庫,現在系統A需要校驗身份,校驗這個過程是系統A獨有的嗎,顯然不是,原則上調用任何一個系統的接口都需要驗證權限,只有權限通過了纔可以調用,那麼校驗這個肯定是上述場景中的一步,爲此上面的場景抽象爲五步:組裝參數、校驗權限、發送請求、處理返回參數、保存數據。而且校驗權限這個肯定每個系統的驗證方式是不一樣的,所以需要每個實現類定義自己的實現,也就是它必須是一個抽象的方法

  現在還有一個實際的問題,系統A需要校驗權限,系統B不需要,兩個實現類均實現了校驗權限的方法,豈不是都會進行校驗,可不可以判斷下是否需要校驗,而且這個判斷最好交給實現類來實現,由實現類決定是否需要校驗。爲此上面的UML變成了下面的樣子,

  上面的UM類圖有什麼玄機嗎,聰明的你肯定看出來了,我再絮叨絮叨。在AbastractSyncData抽象類中增加了抽象方法checkAuthority()和非抽象方法isCheckAuthority(),在SyncSystemAImpl類中實現了checkAuthority()方法和isCheckAuthority()方法,而SyncSystemBImpl僅實現了checkAuthority()方法,怎麼樣和我說的一樣吧。

二、最新實現

下面看下現在的每個類,SyncData接口無變化,這裏不再貼出,

AbstractSyncData.java

package com.example.template;

import java.util.Map;

public abstract class AbstractSyncData implements SyncData {
    //定義好同步數據的步驟
    @Override
    public void syncData() {
        //1、組裝參數
        Map param = assembleParam();
        //新增步驟:判斷是否需要校驗權限
        if (isCheckAuthority()) {
            checkAuthority();
        }
        //2、發送請求
        String result = sendRequest(param);
        //3、解析
        String result2 = parse(result);
        //4、保存數據
        saveData(result2);
    }

    //校驗權限
    protected abstract void checkAuthority();

    //是否校驗權限,由該方法決定是否調用checkAuthority()方法,默認爲false不校驗
    protected boolean isCheckAuthority() {
        return false;
    }

    //1、組裝參數,供子類實現自己的邏輯
    protected abstract Map assembleParam();

    //2、發送請求
    private String sendRequest(Map map) {
        //實際發送請求,並把數據返回
        System.out.println("發送請求");
        return "";
    }

    //3、解析返回結果,供子類實現自己的邏輯
    protected abstract String parse(String result);

    //4、保存數據
    private void saveData(String result) {
        System.out.println("保存數據");
    }
}

SyncSystemAImpl.java

package com.example.template;

import java.util.HashMap;
import java.util.Map;

public class SyncSystemAImpl extends AbstractSyncData {
    @Override
    protected void checkAuthority() {
        System.out.println("校驗系統A的權限");
    }

    @Override
    protected Map assembleParam() {
        System.out.println("組裝發送到系統A的參數");
        return new HashMap();
    }

    @Override
    protected String parse(String result) {
        System.out.println("解析系統A的返回結果");
        return "";
    }

    /**
     * 重寫父類的方法
     *
     * @return
     */
    @Override
    protected boolean isCheckAuthority() {
        return true;
    }
}

SyncSystemBImpl.java

package com.example.template;

import java.util.HashMap;
import java.util.Map;

public class SyncSystemBImpl extends AbstractSyncData {
    @Override
    protected void checkAuthority() {
        System.out.println("校驗系統B的權限");
    }

    @Override
    protected Map assembleParam() {
        System.out.println("組裝發送到系統B的參數");
        return new HashMap();
    }

    @Override
    protected String parse(String result) {
        System.out.println("解析系統B的返回結果");
        return "";
    }
}

看下測試結果,

組裝發送到系統A的參數
校驗系統A的權限
發送請求
解析系統A的返回結果
保存數據
-----------
組裝發送到系統B的參數
發送請求
解析系統B的返回結果
保存數據

Process finished with exit code 0

  從上面的結果可以看到在讀取系統A的接口時多了“校驗系統A的權限”,而系統B卻沒有,滿足上面的要求。說了那麼多多總算要給今天的主角正名,isCheckAuthority()方法我們稱之爲鉤子方法。isCheckAuthority()方法在父類(抽象類)中聲明,且提供了默認的實現,那麼不管子類是否覆蓋該方法都可以,這就是鉤子方法的高明之處。

  在模板方法模式中鉤子方法由抽象類聲明並提供默認實現,該方法不要求子類一定去實現,所以不是抽象方法,子類可以選擇@Override該方法也可以選擇不這麼做,如果不這麼做將會使用父類的邏輯,如果這麼做了則使用子類的邏輯。鉤子方法要在算法的骨架中有所體現。

  有了鉤子方法可以讓子類有更多的自主處理邏輯的能力,在不改變算法骨架的前提下提供了更多的便利,使模板方法模式更好用。希望大家在日常的開發中多思考功能場景,儘量對問題進行抽象,從抽象中尋找共性,針對差異化的處理就可以使用“鉤子方法”了。

  今天的分享就到這裏,感謝你能喜歡,下次見。

 

推薦閱讀

《源碼中的設計模式--模板方法模式》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章