模板方法模式 Template method 行為型 設計模式(二十六)


模板方法模式 Template method
image_5c230441_24ee
上圖為網上百度的一份簡歷模板截圖
 
image_5c230441_1b35
相信大家都有求職的經歷,那么必然需要簡歷,寫簡歷的時候,很可能你會網上檢索一份 簡歷模板,使用此模板的格式,然后替換為你的內容。 
 
我們從小就有語文課,逢考必有作文,而學習的途徑之一就是參考優秀的 范文,學習了解他們的結構,風格等。
image_5c230441_782a
以上就是現實世界中的模板,模板的概念隨處可見,所有的工業制品哪個不是 模具生產的?
 
在程序設計中,也有模板的概念
在軟件開發過程中,可能經常會用到類似的處理邏輯,但是可能又有一些細節的差異
比如做菜,不管做什么菜,基本上都離不開買菜,洗菜,切菜,做菜幾個主要步驟
這幾個步驟中,只有做菜的差別最大,不同的菜不同的做法,而買菜洗菜切菜的過程,卻基本類似
 
我們常常希望能夠 定義一個通用的處理框架,然后將一部分實現細節交由子類進行處理
也就是 面向框架進行編程,而不是每次都復制粘貼修改代碼,具體的細節依靠子類確定,這就是模板的初衷。 
 
比如定義一個做菜的抽象類,實現了買菜,洗菜,切菜,做菜方法定義為抽象方法留待子類實現
那么,回鍋肉和大頭菜就可以通過繼承擴展做菜類,只需要實現做菜的環節即可。

意圖

定義一個操作中的算法的骨架,而將一些步驟延時到子類中。
TemplateMethod使得子類可以不改變一個算法的結構即可重新定義算法的某些特定步驟。

結構

image_5c230441_6923
 
抽象模板角色AbstractClass
定義一個或者多個抽象步驟,這些抽象操作叫做基本操作
他們可能是一個復雜操作的組成步驟
實現類角色ConcreteClass
實現父類所定義的一個或者多個抽象方法
 
每一個抽象模板都可以有任意多個具體的模板角色與之對應,而實際中,一般不止一個

代碼示例

定義做菜步驟:買菜,洗菜,切菜,做菜。
買菜、洗菜、切菜都一樣,做菜不同菜不同做法
上菜將他們步驟進行打包
package template;
 
public abstract class 做菜 {
    public void 買菜(){
        System.out.println("買菜...");
    }
    public void 洗菜(){
        System.out.println("洗菜...");
    }
    public void 切菜(){
        System.out.println("切菜...");
    }
    public abstract void 做菜();
     
    public void 上菜(){
        買菜();
        洗菜();
        切菜();
        做菜();
        System.out.println("客官,菜來了~~~");
    }
}
做回鍋肉和做大頭菜都重寫了“做菜”的方法
package template;
 
public class 做回鍋肉 extends 做菜 {
@Override
public void 做菜() {
System.out.println("做回鍋肉...");
}
}

 

package template;
public class 做大頭菜 extends 做菜 {
@Override
public void 做菜() {
System.out.println("做大頭菜...");
}
}

測試代碼

image_5c230442_6920

方法分類

通常模板模式中會涉及到兩類方法,模板方法和基本方法
模板方法指的是定義在抽象類中,把基本方法組合在一起形成復雜邏輯的方法,通常子類是不修改這個方法的
模板方法給出來頂層的邏輯框架。
比如上面的“上菜”,上菜方法調用了“買菜,洗菜,切菜,做菜”
可以有任意多個的模板方法
 
另一類就是 基本方法了,基本方法就是復雜方法的組成部分
基本方法又有幾種形式
抽象方法,具體方法,鈎子方法
抽象方法:abstract定義,子類實現
具體方法:抽象類具體實現
鈎子方法:抽象類提供默認實現的方法,經常是一個空實現,好處是子類不是必須實現
 
前面說到,模板方法定義了頂層的框架邏輯,而且子類一般不修改,直接繼承。
可以通過鈎子方法對頂層框架邏輯進行微調
比如上面做菜的示例中,上菜的環節中,新增加一個方法用來判斷是否需要切菜
image_5c230442_711e
 
做大頭菜類中,重寫這個方法,做大頭菜,不切了
image_5c230442_6905
 
再來看看打印結果,大頭菜,沒切就做了。。。。。
image_5c230442_1cd4

總結

模板方法模式的根本在於共性的提取與解題步驟框架化
通常使用繼承機制完成這一目標
 
繼承使得類型的等級結構易於理解,層次分明,非常適合抽象化的設計
但是 繼承隨之而來的強耦合,也將會導致很多的不便,比如打破了封裝,父類向子類暴露
不能在運行時動態更改,父類改變,子類很可能也需要改變
所以繼承是一把雙刃劍,使用不當也會導致很大的問題。
但是,不能因噎廢食,個人認為對繼承的態度應該是 不濫用,不棄用
 
模板模式也可以用於方法層次上 方法的拆解,如果一個方法中有很多的代碼邏輯步驟
那么,可以借助於模板模式定義解題步驟,將步驟進行拆解
比如原方法為
step()
拆分后為
step(){
  step1();
  step2();
  ....
}
原來的step的方法就相當於抽象類,step1,step2就相當於具體的子類
 
模板模式的根本就是共性的提取以及解題步驟框架化(就是步驟分明處理)
所以千萬不要認為模板就僅僅只是繼承,實現接口就表示模板的概念了么?個人認為仍舊是
沒有模板方法,僅僅是基本方法就不是模板模式了么?個人認為仍舊是
模板方法仍舊是依賴倒置原則的實現方案。
只不過模板模式相對於面向抽象編程,又進一步期望父類提供更多給子類,比如算法邏輯框架
將部分職責延遲到子類。
 
借助於鈎子方法的形式,可以引入更多的靈活性,子類可以對父類的整體邏輯做出微調
達到了反向控制的效果---子類控制了父類方法的細節步驟
 
涉及到共性提取或者框架步驟分割的都可以考慮模板模式
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM