模板方法模式定義了一個算法的步驟,並容許子類別爲一個或多個步驟提供其實踐方式。讓子類別在不改變算法架構的狀況下,從新定義算法中的某些步驟。(維基百科)java
定義中提到,模板方法定義了一個算法的步驟,容許子類爲一個或者多個步驟提供其實踐方式。也就說在這個模式中,算法的步驟是已經肯定的。可是不一樣的子類中可能會有算法的步驟的具體實現。這樣的話,就至關於父類中有算法的步驟,可是把具體的算法的步驟延遲到子類中去實現。這樣就實現了算法的步驟和算法的步驟的具體實現分離。若是在有一種新的算法的實現,就再寫一份子類就能夠了。算法
模板方法模式的使用場景以下:若干個類有步驟相同的邏輯,可是步驟的實現方法不一樣。複雜的算法,能夠把核心算法設計爲模板方法,具體的相關細節由子類去實現。舉一個例子:Pascal君和java君在餐廳點完餐以後,想要吃飯。(不要問我爲何Scala君不見了-_-)他們吃飯的步驟以下。準備餐具,吃飯,收拾餐具。可是Pascal君和java君準備的餐具不一樣,吃飯的樣子不同,而且Pascal君不喜歡收拾餐具。而java君每次吃飯後都要本身收拾餐具。設計模式
咱們分析二者的不一樣處和共同的地方,相同的地方是,java君和Pascal君的吃飯的步驟,都是分三步,準備餐具,吃飯,收拾餐具,不一樣的地方就是三個步驟的具體實現不一樣,咱們嘗試把相同的步驟提取出來,這些步驟就屬於模板方法。咱們將其封裝到父類中,這個父類能夠是一個抽象類,而後讓子類去繼承父類,而後子類去具體實現具體的被模板調用的方法,這樣就把變化的部分和不變的部分分離開了。架構
package template_method; /* * Created by 王鏡鑫 on 2016/10/9 */ public abstract class Meal//抽象模板類 { protected abstract void prepareTableWare();//基本方法 準備餐具 protected abstract void eat();//基本方法 吃飯 protected abstract void clean();//基本方法 清理餐具 final public void start()//模板方法。調用基本方法,完成相關的邏輯 { prepareTableWare(); eat(); clean(); } } class JAVAMeal extends Meal//具體的java君吃飯 { protected void prepareTableWare()//實現java君特有的準備餐具 { System.out.println("I prepare a knives and forks!"); } protected void eat()//實現java君特有的吃 { System.out.println("I eat slowly!"); } protected void clean()//實現java君特有的清理 { System.out.println("I do cleaning"); } } class PascalMeal extends Meal//具體的Pascal君吃飯 { protected void prepareTableWare()//實現Pascal君特有的準備餐具 { System.out.println("I prepare a chopsticks!"); } protected void eat()//實現Pascal君特有的吃 { System.out.println("I eat quick!"); } protected void clean()//實現Pascal君特有的清理 { System.out.println("I do not do any cleaning"); } } class Work { public static void main(String[] args) { Meal javaMeal = new JAVAMeal(); javaMeal.start(); Meal pascalMeal = new PascalMeal(); pascalMeal.start(); } }
該代碼的輸出結果以下:ui
I prepare a knives and forks! I eat slowly! I do cleaning I prepare a chopsticks! I eat quick! I do not do any cleaning
這裏有幾點要注意的地方:咱們通常將父類的模板方法加上final關鍵字,防止被惡意覆蓋,父類的抽象基本方法咱們通常用protected修飾符修飾,讓其對除了子類和同包下的類可見。
咱們能夠看到,模板方法模式十分簡單,在平時的設計中應用也很是普遍。模板方法模式通常分紅兩部分,模板類和具體實現類。模板類中定義了具體的算法的實現步驟,和抽象的步驟的具體實現,而後子類繼承抽象父類,而後去實現具體的步驟。模板方法模式封裝了不變的部分,擴展了可變的部分。使用模板方法模式,能夠很容易的擴展業務邏輯,若是Scala君也想要吃飯,咱們只要讓他去繼承Meal類。而後實現具體的準備餐具,進食,收拾餐具步驟便可。咱們根本不用修改原來已經存在的代碼。符合對修改關閉,對擴展開放的設計原則。講到這裏,各位看官可能有疑問了。既然Pascal君吃飯不收拾桌子,咱們乾脆不讓他調用這個方法不就能夠了。若是按照如今這個寫法。咱們只能固定的調用這麼多步驟,然而咱們在具體的項目中多是有些步驟能夠省略的,好比Scala君喜歡用手抓着吃。那麼他就不用準備餐具了。這樣在調用準備餐具的方法,不是畫蛇添足了嗎?沒錯。的確有這樣的問題,由於當前咱們的模板方法沒法對子類進行行爲約束,咱們的解決方案就是使用鉤子方法。鉤子方法的概念很簡單。其實就是在父類中增長了is***的抽象方法,而後本身具體實現,返回true或者false代表是否須要調用這個方法。在父類的模板方法中先判斷是否能夠執行,而後在執行該步驟,這些個is***方法就是鉤子方法,顧名思義,鉤子能夠鉤取這些基本方法,控制其是否執行。鉤子方法是一種很形象的叫法。
模板方法模式是一種很簡單的設計模式。簡單到咱們一直在用殊不知道。咱們將這種模式抽象出來,造成通常化的模式,而後取一個名字,在解決各類設計問題的時候,咱們一說這個名字,你們都懂,這就是規範的力量。舉一個在平時用到模板方法模式的例子:servlet中的對一個請求進行具體的業務邏輯處理。是調用了Httpservlet中的service方法,而後service方法根據不一樣的請求分發到具體的方法中,而具體的業務邏輯則由用戶去繼承HttpServlet類去實現,這就是一個常見的模板方法模式的應用。spa
本文轉載自王鏡鑫的我的博客 » 【原創】設計模式系列(二)——模板方法模式設計