模板方法模式--封裝演算法
模板方法模式:在一個方法中定義一個演算法的步驟,而將一些步驟延遲到子類中。模板方法使得子類在不改變演算法結構的情況下,重新定義演算法的某些步驟。
下面用一個例子來詳細解釋一下。
有些人沒有咖啡就活不下去,有些人離不開茶,兩者共同的成分是什麼?當然是咖啡因了。但,還不只是這樣,茶和咖啡的沖泡方式非常相似,不信你瞧瞧:
星巴茲咖啡沖泡法:
(1) 把水煮沸
(2) 用沸水沖泡咖啡
(3) 把咖啡倒進杯子
(4) 加糖和牛奶
星巴茲茶沖泡法:
(1) 把水煮沸
(2) 用沸水浸泡茶葉
(3) 把茶倒進杯子
(4) 加檸檬
那用程式碼實現就是:
public class Coffee {
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}
public void pourInCup() {
System.out.println("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("Add lemon");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
我們發現了重複的程式碼,這是好現象。這表示我們需要清理一下設計了。在這裡,既然茶和咖啡師如此的相似,似乎我們應該把共同的部分抽出來,放進一個基類裡。
看起來這個咖啡和茶的設計練習是相當的直接,你的第一版設計看起來是這樣:
CaffeineBeverage:
prepareRecipe();
boilWater();
pourInCup();
Coffee:
prepareRecipe();
brewCoffeeGrinds();
addSugarAndMilk();
Tea
prepareRecipe();
steepTeaBag();
addLemon();
我們的新設計你 覺得怎麼樣?是不是覺得忽略了某些其他共同點?咖啡和茶還有什麼是相似的?我們先從沖泡法入手
(1) 把水煮沸
(2) 用沸水沖泡咖啡
(3) 把咖啡倒進杯子
(4) 加糖和牛奶
(1)、(3)我們已經抽出來放到基類裡了,(2)、(4)並沒有被抽出來,但是他們是一樣的,只是應用在不同的飲料上。那麼我們有辦法將prepareRecipe()也抽象化嗎?是的,現在就來看看該怎麼做,讓我們從每一個子類中逐步抽象prepareRecipe(),我們遇到的第一個問題,就是咖啡使用brewCoffeeGrinds()和addSugarAndMilk()方法,而茶使用的是steepTeaBag()和addLemon()方法。
讓我們來思考這一點,浸泡(steep)和沖泡(brew)差異其實不大,所以我們給他一個新的方法名稱,比方說brew(),然後不管泡茶還是沖泡咖啡我們都用這個名稱。類似的,加糖和牛奶也和加檸檬很相似,都是在飲料中加入調料,讓我們也用一個新的方法名稱來解決這個問題,就叫做addCondiments()好了。這樣一來,新的prepareRecipe()方法看起來就是這樣:
void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
現在我們有了新的prepareRecipe()方法,但是需要讓他能夠符合程式碼。要想這麼做,我們就先從CaffeineBeverage()超類開始:
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
最後我們就需要處理咖啡和茶類了,這兩個類現在都是依賴超類來處理沖泡法,所以只需自行處理沖泡和新增調料部分:
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");
}
}
基本上,我們剛剛實現的就是模板方法模式。模板方法定義了一個演算法的步驟,並允許子類為一個或多個步驟提供實現。
從上面我們可以看出,模板方法模式的優勢就是:
1、可以將程式碼的複用最大化。
2、演算法只存在於一個地方,所以容易修改。
3、這個模板提供了一個框架,可以讓其他的咖啡因飲料插進來。
4、CaffeineBeverage類專注在演算法本身,而由子類提供完整的實現。
相關文章
- 模板方法模式-封裝一套演算法流程模式封裝演算法
- 模板方法模式模式
- 模板方法模式(Template)模式
- javascript模板方法模式JavaScript模式
- 策略模式與模板方法模式模式
- 設計模式-模板方法模式設計模式
- 設計模式 ——— 模板方法模式設計模式
- 命令模式 & 策略模式 & 模板方法模式
- 演算法的封裝與切換——策略模式(三)演算法封裝模式
- 演算法的封裝與切換——策略模式(二)演算法封裝模式
- Java設計模式-模板方法模式Java設計模式
- 設計模式之【模板方法模式】設計模式
- js設計模式--模板方法模式JS設計模式
- 設計模式之模板方法模式設計模式
- 設計模式-模板方法模式.md設計模式
- 設計模式(五)——模板方法模式設計模式
- 模板方法設計模式設計模式
- 淺談模板方法模式模式
- 【設計模式】--模板方法設計模式
- 單體模式封裝模式封裝
- 【封裝小技巧】is 系列方法的封裝封裝
- PHP設計模式之模板方法模式PHP設計模式
- 簡說設計模式——模板方法模式設計模式
- python設計模式-模板方法模式Python設計模式
- 設計模式實戰-模板方法模式設計模式
- 極簡設計模式-模板方法模式設計模式
- 【大話設計模式】—— 模板方法模式設計模式
- 設計模式之模板方法設計模式
- 聊一聊模板方法模式模式
- 模板方法模式深度解析(三)模式
- 模板方法模式深度解析(二)模式
- 模板方法模式深度解析(一)模式
- Java描述設計模式(19):模板方法模式Java設計模式
- C#設計模式(14)——模板方法模式C#設計模式
- 《Head First 設計模式》:模板方法模式設計模式
- Java設計模式之(十三)——模板方法模式Java設計模式
- javascript設計模式 之 8 模板方法模式JavaScript設計模式
- 我的Java設計模式-模板方法模式Java設計模式