在上次《原始碼中的設計模式--模板方法模式》中分享了有關模板方法設計模式方面的東西,不知道還有印象沒,重溫下其釋義,
模板方法模式在一個方法中定義一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變演算法結構的情況下,重寫定義演算法中的某些步驟。
在上次中舉了這樣的場景,要呼叫系統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該方法也可以選擇不這麼做,如果不這麼做將會使用父類的邏輯,如果這麼做了則使用子類的邏輯。鉤子方法要在演算法的骨架中有所體現。
有了鉤子方法可以讓子類有更多的自主處理邏輯的能力,在不改變演算法骨架的前提下提供了更多的便利,使模板方法模式更好用。希望大家在日常的開發中多思考功能場景,儘量對問題進行抽象,從抽象中尋找共性,針對差異化的處理就可以使用“鉤子方法”了。
今天的分享就到這裡,感謝你能喜歡,下次見。
推薦閱讀