設計模式之模板方法模式(一)

學習了前面的朋友都知道,目前爲止,咱們的議題都是繞着封裝轉;咱們已經封裝了對象建立、方法調用、複雜接口、鴨子、比薩...那接下來呢java

咱們將要深刻封裝算法塊、好讓子類能夠在任什麼時候候均可以將本身掛接進運算裏。咱們甚至會在這裏學到一個受好萊塢影響而啓發的設計原則。算法

喝點咖啡或茶飲

有些人喜歡喝咖啡,沒有咖啡感受生活索然無趣;有些人喜歡喝茶。那麼,一樣是茶飲,二者有沒有什麼共同或者是啥的?其實,二者的沖泡方式很是類似。好比學習

  1. 咖啡沖泡法
  • (1)把水煮沸
  • (2)用沸水沖泡咖啡
  • (3)把咖啡倒進杯子
  • (4)加糖和牛奶
  1. 茶飲沖泡法
  • (1)把水煮沸
  • (2)用沸水浸泡茶葉
  • (3)把茶倒進杯子
  • (4)加檸檬

轉換成咖啡和茶的代碼以下:設計

public class Coffee {
    void prepareRecipe() {
        boilWater();
        brewCoffeeGrinds();
        pourInCup();
        addSugarAndMilk();
    }

    public void boilWater() {
        System.out.println("Boling water");
    }

    public void brewCoffeeGrinds() {
        System.out.println("Dripping Coffee through filter");
    }

    public void pourInCup() {
        System.out.print("Pouring into cup");
    }

    public void addSugarAndMilk() {
        System.out.println("Adding Sugar and Milk");
    }
}

public class Tea {
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void steepTeaBag() {
        System.out.println("Steeping the tea");
    }

    public void addLemon() {
        System.out.println("Adding Lemon");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

茶類也是相似的,因此就會出現代碼又相通的地方,給咱們的提示就是,初版的設計類圖能夠是以下的方式:3d

更進一步的設計

因此,查看了以上的代碼和類圖,咖啡和茶還有什麼其餘的共同點呢?讓咱們先從沖泡法下手。code

  1. 把水煮沸
  2. 用熱水泡咖啡或茶
  3. 把飲料倒進杯子
  4. 在飲料內加入適當的調料

能夠看到,1和4已經被抽出來,放到了基類中。2和3並無抽出來,但它們本質仍是同樣的,只是應用在不一樣的飲料上罷了。對象

那麼,咱們有辦法將prepareRecipe()也抽象化嗎?是的,咱們能夠哦blog

抽象prepareRecipe()

  1. 咱們所遇到的第一個問題,就是咖啡使用brewCoffeeGrinds()和addSuagrAndMilk()方法,而茶使用steepTeaBag()和addLemon().

咱們發現,steep和brew都是泡的動做;addSugarAndMilk和addLemon都是加調料,因此分別把他們統一成brew()和addCondiments()進行接口

  1. 如今咱們有了新的prepareRecipe()方法,可是須要讓它可以符合代碼。要想這麼作,咱們先從CaffeineBeveage(咖啡因飲料)超類開始
public abstract  class CaffeineBeverage {
    final void prepareRecipe() {

    }

    abstract  void brew();

    abstract  void addCondiments();

    void boilWater() {
        System.out.println("Boiling water");
    }

    void pourInCup() {
        System.out.println("Pouring into cup");
    }
}
  1. 最後咱們須要處理咖啡和茶類了。這兩個類如今都依賴超類(咖啡因飲料)來處理沖泡法,因此只須要自行處理沖泡和添加調料部分便可:
public class Tea extends CaffeineBeverage {
    public void brew() {
        System.out.println("Steeping the tea");
    }
    public void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

public class Coffee extends CaffeineBeverage {
    public void brew() {
        System.out.println("Dripping Coffee through filter");
    }
    public void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

那麼咱們在這個過程當中作了什麼呢?小編用書中給出的形象化的圖給你們解釋下:ip

認識模板方法

其實,咱們在這個過程當中已經使用了咱們要學習的模板方法,prepareRecipe()就是咱們的模板方法。爲何呢?

  • 畢竟它是一個方法
  • 它用做一個算法的模板,在這個例子中,算法是用來製做咖啡和茶飲的

模板方法定義了一個算法的步驟,並容許子類爲一個或多個步驟提供實現

讓咱們泡茶喝吧

讓咱們逐步地泡茶、追蹤這個模板方法是如何工做的。你會得知在算法內的某些方法,該模板方法控制了算法。它讓子類可以提供某些步驟的實現

  1. 首先咱們須要一個茶對象
Tea myTea = new Tea();
  1. 而後咱們調用這個模板方法
myTea.prepareRecipe();
  1. 把水煮沸
boilWater();

這件事情是在超類中進行的
  1. 接下來咱們須要泡茶,這件事情只有子類才能知道要怎麼作
brew();
  1. 如今把茶倒進杯子中;全部的飲料作法都同樣,因此這件事情發生在超類中
pourInCup();
  1. 最後,咱們加進調料,因爲調料是各個飲料獨有的,因此 由子類來實現它
addCondiments();

通過上述的流程,咱們就初步模板方法模式給學會了。在今天的篇尾,咱們定義下這個模板方法模式:
模板方法模式:在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠在不改變算法結構的狀況下,從新定義算法中的某些步驟。

這個模式是有歷來建立一個算法的模塊。什麼是模塊?如你所見,模板就是一個方法。更具體地說,這個方法將算法定義成一組步驟,其中的任何步驟均可以是抽象的,由子類負責實現。這能夠確保算法的結構保持不變,同時由子類提供部分實現。

好啦,今天的學習就先到這裏。今天只是初步學習了模板方法模式,接下來還會有更有料的方式,下次不見不散。

愛生活,愛學習,愛感悟,愛挨踢

相關文章
相關標籤/搜索