模板方法模式,定義一個操做中算法的骨架,而將一些步驟延遲到子類中。使得子類能夠不改變一個算法的結構便可從新定義該算法的某些特定步驟。html
模板方法模式,實際上是很好理解的,具體理解爲,定義一個操做中算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠不改變一個算法結構便可衝定義該算法的某些特定步驟。模板方法模式是最爲常見的設計模式之一,是基於繼承的代碼複用技術。架構師定義一套骨架,開發工程師按照骨架去實現具體的邏輯。算法
在具體的項目中其實使用模板方法的場景有不少,就舉我之間遇到過的一個場景吧,這是一個實際的項目,結合這個項目的中的場景能夠引出模板方法模式的使用方法,設計模式
在一個審批流程的項目,會有不少種的申請單,例如:出差申請單、請假申請單、採購申請單、付款申請單等等。每一個申請單在提交的時候都要先校驗申請單的參數是否正確,以及在提交成功後去通知審批人,有待審批的單子了。因此說,這個過程都是同樣的,只不過是,每一個申請單的校驗參數以及通知審批人的方法會有所不一樣。那麼這樣就能夠把這個提交的過程定義成一個模板,而後每一個審批單的都按照這個流程來進行提交申請就能夠了。架構
具體代碼實現以下:框架
流程模板類ide
/** * 流程模板類 */ public abstract class BaseProcess { /** * 提交流程 */ public void submitProcess(Map<String,String> paramMap){ boolean checkResult = checkParameter(paramMap); if(checkResult){ System.out.println("提交流程成功!"); remindApprovers(); }else { System.out.println("提交流程失敗!"); } } /** * 校驗參數 * @return */ public abstract boolean checkParameter(Map<String,String> paramMap); /** * 提醒審批人 */ public abstract void remindApprovers(); }
差旅審批流程post
/** * 差旅審批流程 * */ public class BusinessTravelProcess extends BaseProcess{ /** * 校驗參數 * * @return */ @Override public boolean checkParameter(Map<String,String> paramMap) { if(null!=paramMap.get("result")&¶mMap.get("result").equals("true")){ System.out.println("差旅審批單參數校驗成功!"); return true; }else { System.out.println("差旅審批單參數校驗失敗!"); return false; } } /** * 提醒審批人 */ @Override public void remindApprovers() { System.out.println("有新的差旅申請提交了。"); } }
請假審批流程學習
/** * 請假審批流程 */ public class LeaveApplyProcess extends BaseProcess { /** * 校驗參數 * * @return */ @Override public boolean checkParameter(Map<String,String> paramMap) { if(null!=paramMap.get("result")&¶mMap.get("result").equals("true")){ System.out.println("請假審批單參數校驗成功!"); return true; }else { System.out.println("請假審批單參數校驗成功!"); return false; } } /** * 提醒審批人 */ @Override public void remindApprovers() { System.out.println("有新的請假申請提交了。"); } }
測試類測試
public class Client { public static void main(String[] args) { //建立請假申請單 BaseProcess leaveApply = new LeaveApplyProcess(); Map<String,String> paramMap = Maps.newHashMap(); paramMap.put("result","true"); //提交採購申請單 leaveApply.submitProcess(paramMap); //建立差旅申請單 BaseProcess business = new BusinessTravelProcess(); paramMap = Maps.newHashMap(); paramMap.put("result","false"); //提交差旅申請單 business.submitProcess(paramMap); } }
運行結果url
請假審批單參數校驗成功!
提交流程成功!
有新的請假申請提交了。
差旅審批單參數校驗失敗!
提交流程失敗!
上面的這個例子就是使用的模板方法模式,這個場景是一些業務功能,大致框架是固定的,只是一些具體的實現細節可能不一樣。用模板方法能提升代碼的複用性和系統的靈活性。
下面來分析一下模板方法的具體結構組成,以下是模板方法模式的類圖。
模板方法模式中,具體就兩個角色。
一、AbstractClass(抽象類):在抽象類中定義了一系列基本操做(PrimitiveOperations),這些基本操做能夠是具體的,也能夠是抽象的,每個基本操做對應算法的一個步驟,在其子類中能夠重定義或實現這些步驟。
二、ConcreteClass(具體子類):它是抽象類的子類,用於實如今父類中聲明的抽象基本操做以完成子類特定算法的步驟,也能夠覆蓋在父類中已經實現的具體基本操做。
可是模板方法模式的實現是離不開這三個方法的
一、基本方法
基本方法也稱爲基本操做,是由子類實現的方法,而且在模板方法中被調用。
二、模板方法
模板方法能夠有一個或幾個,通常是一個具體的方法,也就是一個骨架,實現對基本方法的調度,完成固定的邏輯。爲了防止惡意的操做,通常模板方法都加上final關鍵字,不容許被覆寫。
三、鉤子方法
鉤子方法由抽象類聲明並加以實現。可是子類能夠去擴展,子類能夠經過擴展鉤子方法,來影響模板方法的邏輯。抽象類的任務是搭建邏輯的框架,一般由經驗豐富的人員編寫,由於抽象類的好壞直接決定了程序是否穩定。
模板方法模式是基於繼承的代碼複用技術,它體現了面向對象的諸多重要思想,是一種使用較爲頻繁的模式。模板方法模式普遍應用於框架設計中,以確保經過父類來控制處理流程的邏輯順序(如框架的初始化,測試流程的設置等)。
一、在父類中形式化地定義一個算法,而由它的子類來實現細節的處理,在子類實現詳細的處理算法時並不會改變算法中步驟的執行次序。
二、模板方法模式是一種代碼複用技術,它在類庫設計中尤其重要,它提取了類庫中的公共行爲,將公共行爲放在父類中,而經過其子類來實現不一樣的行爲,它鼓勵咱們恰當使用繼承來實現代碼複用。
三、可實現一種反向控制結構,經過子類覆蓋父類的鉤子方法來決定某一特定步驟是否須要執行。
四、在模板方法模式中能夠經過子類來覆蓋父類的基本方法,不一樣的子類能夠提供基本方法的不一樣實現,更換和增長新的子類很方便,符合單一職責原則和開閉原則。
一、須要爲每個基本方法的不一樣實現提供一個子類,若是父類中可變的基本方法太多,將會致使類的個數增長,系統更加龐大,設計也更加抽象,此時,也可結合橋接模式來進行設計。
二、因爲每一個子類的方法會影響到了父類,這裏違反了里氏替換原則,會給程序帶來風險。
一、對一些複雜的算法進行分割,將其算法中固定不變的部分設計爲模板方法和父類具體方法,而一些能夠改變的細節由其子類來實現。
二、各子類中公共的行爲應被提取出來並集中到一個公共父類中以免代碼重複。
三、須要經過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。
想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。