標籤:系統 prot 可變 解決 turn nal 學習經曆 inf 邏輯
標準模板方法
前幾天遇到了小明,相互寒暄了下,感歎了下時間過得很快,畢業後好些同學都沒聯絡了,然後巴拉巴拉從小學、初中、高中、大學簡單回憶了一下上學時候的有趣的事情……
如果用類圖來描述小明的學習生涯,可以簡單描述為:
如果用程式來描述學習的各個階段,可以簡單表示為:
public abstract class Learn { public abstract void goPrimarySchool(); public abstract void goMiddleSchool(); public abstract void goHignSchool(); public abstract void goUniversity(); final public void learnExp() { goPrimarySchool(); goMiddleSchool(); goHignSchool(); goUniversity(); }}
小明的學習經曆可以簡單描述為:
public class XiaoMingLearn extends Learn { @Override public void goPrimarySchool() { System.out.println("6 years primary school"); } @Override public void goMiddleSchool() { System.out.println("3 years primary school"); } @Override public void goHignSchool() { System.out.println("3 years primary school"); } @Override public void goUniversity() { System.out.println("4 years primary school"); }}
小明給大家講述了一下自己的學曆經曆:
@Test public void testTemplateMethod() { XiaoMingLearn xiaoMingLearn = new XiaoMingLearn(); xiaoMingLearn.learnExp(); }
6 years primary school
3 years middle school
3 years high school
4 years university school
上面一段程式在抽象類別Learn 裡定義了上學的各個階段(抽象方法是因為每個人的學習階段各不相同),learnExp裡按時間先後對各個階段進行了先後排序,有相關經曆的人只需要繼承Learn,對自己各個階段個人化實現,然後就可以通過learnExp向別人講述自己的上學經曆。其實這就是一個標準的模板方法模式,來看一下模板方法的定義:
鉤子模板方法
上面例子只是一個標準的模板方法,對於老王而言,初中的時候已經自學完了高中的課程,根本沒上過高中,初中畢業直接被大學免試招生了,老王向別人講述(吹起)自己上學的經曆就沒有高中的階段。對於這種情況,可以在學習流程裡內建一個是否需要上高中的狀態,然後在模板方法裡(learnExp方法)根據狀態來判斷是否調有高中階段即可。用類圖簡單描述為:
Learn抽象方法稍加改造,新增了一個是否需要上高中的標識(isNeedHighSchool)並提供預設值,標識可由子類根據需要覆蓋:
public abstract class Learn { public abstract void goPrimarySchool(); public abstract void goMiddleSchool(); public abstract void goHignSchool(); public abstract void goUniversity(); final public void learnExp() { goPrimarySchool(); goMiddleSchool(); if(isNeedHighSchool()) { goHignSchool(); } goUniversity(); } protected Boolean isNeedHighSchool() { return true; }}
老王的牛逼上學經曆:
public class LaoWangLearn extends Learn { @Override public void goPrimarySchool() { System.out.println("6 years primary school"); } @Override public void goMiddleSchool() { System.out.println("3 years middle school"); } @Override public void goHignSchool() { System.out.println("3 years high school"); } @Override public void goUniversity() { System.out.println("4 years university school"); } @Override protected Boolean isNeedHighSchool() { return false; }}
老王講述自己的經曆:
@Test public void testLaoWang() { LaoWangLearn laoWangLearn = new LaoWangLearn(); laoWangLearn.learnExp(); }
6 years primary school
3 years middle school
4 years university school
小明和老王講述的方法相同,卻有不同的經曆。
同樣的流程,同樣的方法,不同的執行過程,這就是模板方法的變種方式,isNeedHighSchool就是鉤子方法,子類重寫鉤子方法改變父類的執行過程。
模板方法定義
定義:定義一個操作中的演算法的架構,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重新定義該演算法的某些特定步驟。
類圖:
上述老王和小明對應模板方法結構圖為:
總結
主要解決:一些方法通用,卻在每一個子類都重新寫了這一方法。
何時使用:有一些通用的方法。
如何解決:將這些通用演算法抽象出來。
關鍵代碼:在抽象類別實現,其他步驟在子類實現。
應用執行個體:比如開啟事務、擷取 Session、關閉 Session 等,程式員不重複寫那些已經規範好的代碼,直接丟一個實體就可以儲存。
優點: 1、封裝不變部分,擴充可變部分。 2、提取公用代碼,便於維護。 3、行為由父類控制,子類實現。
缺點:每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
使用情境: 1、有多個子類共有的方法,且邏輯相同。 2、重要的、複雜的方法,可以考慮作為模板方法。
注意事項:為防止惡意操作,一般模板方法都加上 final 關鍵詞。
設計模式——模板方法