1. 程式人生 > >設計模式——模板模式(Template Pattern)

設計模式——模板模式(Template Pattern)

  在讀Spring原始碼的時候,發現Spring程式碼中運用了大量的模板模式,比如根據檔案系統目錄載入配置檔案(FileSystemXmlApplicationContext),類路徑載入配置檔案(ClassPathXmlApplicationContext),以及根據專案上下文目錄(XmlWebApplicationContext)載入配置檔案。這個在載入的過程中就使用了模板設計模式,所以特意去學習了一下模板設計模式,從而更好的理解原始碼。

1.模板設計模式在書中的定義

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

  我的翻譯就是:完成一件事情,有固定的數個步驟,但是每個步驟根據物件的不同,而實現細節不同;就可以在父類中定義一個完成該事情的總方法,按照完成事件需要的步驟去呼叫其每個步驟的實現方法。每個步驟的具體實現,由子類完成。

2.舉個例子來說

  小張的團隊最近接受一個需求,實現實現一家咖啡店的沖泡咖啡和茶的沖泡自動化。之前這家咖啡店都是由咖啡師傅手動進行調製咖啡和茶。現在咖啡店需要引入自動化的點單和調製飲料的系統,小張負責實現調製飲料的功能。

  咖啡師傅手工沖泡咖啡和茶的流程:

  沖泡咖啡:

         把水煮沸

              用沸水沖泡咖啡

              把咖啡倒入杯子

              加糖和牛奶

   沖泡茶:

            把水煮沸

            用沸水沖泡茶葉

            把茶倒入杯子

            加檸檬

  使用模板模式實現

  我們首先看一個類圖

  

  程式碼實現

package xuelongjiang.designpartten.templatemethod;

/**
 *
 * 模板方法
 *
 *
 */
abstract   public class CaffeineBeverage {

    //演算法。 抽象類的演算法是final 的不允許被子類修改
     public final  void   prepareRecipe(){

         //演算法的具體步驟
         boilWater(); //燒水
         brew();//沖泡
         pourInCup();// 把飲料倒入杯子
         if(hook()){
             addCondiments();// 加調料
         }

    }


   public  abstract  void brew();

   public   abstract  void addCondiments();


    public void boilWater(){

        System.out.println("燒水");
    }


    public  void pourInCup(){
        System.out.println("把飲料倒入杯子");
    }

    /**
     *  鉤子,具體實現可以對演算法步驟做一些控制
     *
     * @return
     */
    public boolean hook(){
        return true;
    }

}

  可以看到我們在沖泡咖啡/茶的抽象類中有一個hook方法,這個方法就是鉤子方法。預設返回true,如果沖泡咖啡預設是加調料的那麼子類就不用重寫hook方法。

  咖啡類

package xuelongjiang.designpartten.templatemethod;

/**
 *咖啡類
 */
public class Coffee extends  CaffeineBeverage {


    @Override
    public void brew() {
        System.out.println("用沸水沖泡咖啡粉");
    }

    @Override
    public void addCondiments() {
        System.out.println("加糖和牛奶");
    }

    @Override
    public boolean hook() {
        return super.hook();
    }
}

  茶類

package xuelongjiang.designpartten.templatemethod;

/**
 * 茶類
 */
public class Tea extends  CaffeineBeverage {


    @Override
    public void brew() {
        System.out.println("用沸水侵泡茶葉");
    }

    @Override
    public void addCondiments() {
        System.out.println("加檸檬");
    }


    @Override
    public boolean hook() {
        return super.hook();
    }
}

  測試類

package xuelongjiang.designpartten.templatemethod;
/**
 * 測試類
 */
public class TemplateMethodTest {


    public static void main(String[] args) {
        CaffeineBeverage caffeineBeverage = new Tea();
        caffeineBeverage.prepareRecipe();

        System.out.println("-------------------");

        caffeineBeverage = new Coffee();
        caffeineBeverage.prepareRecipe();


    }
}

  

  要點    

    好萊塢原則:別調用(打電話給)我們,我們會呼叫(打電話給)你。(即高層元件對低層元件的方式是:別調用我們,我們會呼叫你們)。

    模版方法定義了演算法的步驟,把這些步驟的實現延遲到了子類。

    模版方法模式為我們提供了一種程式碼複用的重要技巧。

    模版方法的抽象類可以定義具體方法、抽象方法和鉤子。

    抽象方法由子類實現。

    為了防止子類改變模版方法中的演算法,可以將模版方法宣告為final


---------------------
程式碼部分參考:https://blog.csdn.net/u013565163/article/details/79285617