設計模式系列(二)——模板方法模式

概念:

      模板方法模式定義了一個算法的步驟,並容許子類別爲一個或多個步驟提供其實踐方式。讓子類別在不改變算法架構的狀況下,從新定義算法中的某些步驟。(維基百科)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

本文轉載自王鏡鑫的我的博客 » 【原創】設計模式系列(二)——模板方法模式設計

相關文章
相關標籤/搜索