模板模式可以理解成步驟模式,加入做成一件事情可以有清晰的步驟可循,這件事情就可以套用模板模式來實現。模板的概念應該很多同學都很熟悉,寫一個簡歷,寫一篇論文,假如有一個模板供我們參考的話,寫起來就會更加容易,更加得心應手。這個簡歷模板和論文模板就可以認為是指定了寫簡歷和寫論文的步驟,我們只要按照這個步驟一步步編寫即可。
模板模式的UML類圖如下:
這裡我們通過一個生活中的實例,炒菜來講解一下如何使用模板模式。對於新手來說,炒菜就是按照一步步的步驟來的,大致可以分為 生火-加入食用油-加入菜-加入佐料-裝盤 這幾個步驟。通過代碼來一一實現,首先新建一個抽象類,作為模板類:
AbstractCookTemplate.java(對應類圖中的AbstractClass):
package com.template.demo; public abstract class AbstractCookTemplate { public final void cook(){ System.out.println("--------開始做飯-----------"); fire();//生火 oil();//倒入油 chaocai();//炒菜 zuoliao();//加佐料 zhuangpan();//裝盤 System.out.println("--------結束做飯-----------"); } protected void zhuangpan() {//設置權限protected,方便子類覆寫 System.out.println("裝盤"); } protected void zuoliao() { System.out.println("加入佐料"); } protected void chaocai() { System.out.println("炒菜"); } protected void oil() { System.out.println("加入油"); } protected void fire() { System.out.println("生火"); } }
有些英文比較難,鑒於樓主英文水平有限就用拼音代替了,實際開發中這種方式不可取。
實現類-CookChicken.java(對應ConcreteClassA):
package com.template.demo; public class CookChicken extends AbstractCookTemplate { @Override protected void chaocai() { System.out.println("炒雞肉"); } }
實現類-CookFish.java(對應ConcreteClassB):
package com.template.demo; public class CookFish extends AbstractCookTemplate { @Override protected void zhuangpan() { System.out.println("魚要裝入大盤"); } }
測試類:
package com.template.demo; public class TestClass { public static void main(String[] args) { AbstractCookTemplate abstractCookTemplate=new CookChicken(); abstractCookTemplate.cook(); AbstractCookTemplate abstractCookTemplate2=new CookFish(); abstractCookTemplate2.cook(); } }
運行測試類:
例子比較牽強,嗯哼,大家理解即可。話說又有人說了,假如要涼拌個黃瓜,不需要生火,這時該怎麼辦呢?
這時我們可以使用鉤子方法來實現,具體是什麼樣的鉤子,可以參照代碼:
AbstractCookTemplate.java(對應類圖中的AbstractClass):
package com.template.demo; public abstract class AbstractCookTemplate { public final void cook(){ System.out.println("--------開始做飯-----------"); if(!isColdFood()){ fire();//生火 } oil();//倒入油 chaocai();//炒菜 zuoliao();//加佐料 zhuangpan();//裝盤 System.out.println("--------結束做飯-----------"); } protected boolean isColdFood() {//作為鉤子 return false; } protected void zhuangpan() {//設置權限protected,方便子類覆寫 System.out.println("裝盤"); } protected void zuoliao() { System.out.println("加入佐料"); } protected void chaocai() { System.out.println("炒菜"); } protected void oil() { System.out.println("加入油"); } protected void fire() { System.out.println("生火"); } }
我們可以看出在生火實現之前先進行判斷,若是不是涼拌才允許生火方法。默認是生火的。
若不需要生火方法,在實現類中覆寫isColdFood()方法,返回true即不運行fire()方法。
這時我們實現一個實現類,涼拌黃瓜如下:
package com.template.demo; public class CookCucumber extends AbstractCookTemplate { @Override protected boolean isColdFood() { return true; } }
在測試類中添加 涼拌黃瓜的實現:
package com.template.demo; public class TestClass { public static void main(String[] args) { AbstractCookTemplate abstractCookTemplate=new CookChicken(); abstractCookTemplate.cook(); AbstractCookTemplate abstractCookTemplate2=new CookFish(); abstractCookTemplate2.cook(); AbstractCookTemplate abstractCookTemplate3=new CookCucumber(); abstractCookTemplate3.cook(); } }
然後運行實例:
這時可以看出來,最後一個生活的方法沒有運行,同理,可以用 鉤子方法 決定其他方法是否運行,這樣我們的模板將會更加靈活,應對各種需求。