模板方法模式是行爲型設計模式,原理和代碼實現都比較簡單。算法
定義一個操做中的算法的框架,而將一些步驟延遲到子類中,使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。設計模式
一個父類下面的子類經過繼承父類而使用通用的邏輯,同時根據各自須要優化其中某些步驟一個父類下面的子類經過繼承父類而使用通用的邏輯,同時根據各自須要優化其中某些步驟服務器
舉個拉鉤教育上的例子,設計一個簡單的持續集成發佈系統,研發部開發的代碼放在GitLab
上,並使用一個固定的發佈流程來進行程序的上線發佈。markdown
public abstract class DeployFlow {
//使用final關鍵字來約束步驟不能輕易修改
public final void buildFlow() {
pullCodeFromGitlab(); //從GitLab上拉取代碼
compileAndPackage(); //編譯打包
copyToTestServer(); //部署測試環境
testing(); //測試
copyToRemoteServer(); //上傳包到線上環境
startApp(); //啓動程序
}
public abstract void pullCodeFromGitlab();
public abstract void compileAndPackage();
public abstract void copyToTestServer();
public abstract void testing();
private void copyToRemoteServer() {
System.out.println("統一自動上傳 啓動App包到對應線上服務器");
}
private void startApp() {
System.out.println("統一自動 啓動線上App");
}
}
複製代碼
分別實現兩個子類:一、實現本地的打包編譯和上傳;二、實現全自動化的持續集成式的發佈框架
public class LocalDeployFlow extends DeployFlow{
@Override
public void pullCodeFromGitlab() {
System.out.println("手動將代碼拉取到本地電腦......");
}
@Override
public void compileAndPackage() {
System.out.println("在本地電腦上手動執行編譯打包......");
}
@Override
public void copyToTestServer() {
System.out.println("手動經過 SSH 上傳包到本地的測試服務......");
}
@Override
public void testing() {
System.out.println("執行手工測試......");
}
}
public class CicdDeployFlow extends DeployFlow{
@Override
public void pullCodeFromGitlab() {
System.out.println("持續集成服務器將代碼拉取到節點服務器上......");
}
@Override
public void compileAndPackage() {
System.out.println("自動進行編譯&打包......");
}
@Override
public void copyToTestServer() {
System.out.println("自動將包拷貝到測試環境服務器......");
}
@Override
public void testing() {
System.out.println("執行自動化測試......");
}
}
複製代碼
運行一個單元測試ide
public class Client {
public static void main(String[] args) {
System.out.println("開始本地手動發佈流程======");
DeployFlow localDeployFlow = new LocalDeployFlow();
localDeployFlow.buildFlow();
System.out.println("********************");
System.out.println("開始 CICD 發佈流程======");
DeployFlow cicdDeployFlow = new CicdDeployFlow();
cicdDeployFlow.buildFlow();
}
}
//輸出結果
開始本地 手動發佈流程======
手動將代碼拉取到本地電腦......
在本地電腦上手動執行 編譯打包......
手動經過 SSH 上傳包 到 本地的測試服務......
執行手工測試......
統一自動上傳 啓動App包到對應線上服務器
統一自動 啓動線上App
********************
開始 CICD 發佈流程======
持續集成服務器將代碼拉取到節點服務器上......
自動進行編譯&打包......
自動將包拷貝到測試環境服務器......
執行 自動化 測試......
統一自動上傳 啓動App包到對應線上服務器
統一自動 啓動線上App
複製代碼
從上面場景的分析中,咱們能看出,模板方法模式應用場景的最大特徵在於,一般是對算法的特定步驟進行優化,而不是對整個算法進行修改。一旦總體的算法框架被定義完成,子類便沒法進行直接修改,由於子類的使用場景直接受到了父類場景的影響。函數
不符合開閉原則。 一個父類調用子類實現操做,經過子類擴展增長新的行爲,可是子類執行的結果便會受到父類的影響,不符合開閉原則的「對修改關閉」。單元測試
增長代碼閱讀的難度。 因爲父類的某些步驟或方法被延遲到子類執行,那麼須要跳轉不一樣的子類閱讀代碼邏輯,若是子類的數量不少的話,跳轉會不少,不方便聯繫上下文邏輯線索。測試
違反里氏替換原則。 雖然模板方法模式中的父類會提供通用的實現方法,可是延遲到子類的操做便會變成某種定製化的操做,一旦替換子類,可能會致使父類不可用或總體邏輯發生變化。優化