## 介紹
模板方法(TemplateMethod)定義了一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
模板方法是一種代碼復用的基本技術,在類庫中尤為重要,因為他們提取了類庫中的公共行為。模板方法導致一種反向的控制結構,這種結構就是傳說中的“好萊塢法則”,即“別找找我們,我們找你”,這指的是父類調用一個類的操作,而不是相反。具體體現是面向對象編程編程語言里的抽象類(以及其中的抽象方法),以及繼承該抽象類(和抽象方法)的子類。
## 正文
舉個例子,泡茶和泡咖啡有同樣的步驟,比如燒開水(boilWater)、沖泡(brew)、倒在杯子里(pourOnCup),加小料(addCondiments)等等。但每種飲料沖泡的方法以及所加的小料不一樣,所以我們可以利用模板方法實現這個主要步驟。
首先先來定義抽象步驟:
~~~
var CaffeineBeverage = function () {
};
CaffeineBeverage.prototype.prepareRecipe = function () {
this.boilWater();
this.brew();
this.pourOnCup();
if (this.customerWantsCondiments()) {
// 如果可以想加小料,就加上
this.addCondiments();
}
};
CaffeineBeverage.prototype.boilWater = function () {
console.log("將水燒開!");
};
CaffeineBeverage.prototype.pourOnCup = function () {
console.log("將飲料到再杯子里!");
};
CaffeineBeverage.prototype.brew = function () {
throw new Error("該方法必須重寫!");
};
CaffeineBeverage.prototype.addCondiments = function () {
throw new Error("該方法必須重寫!");
};
// 默認加上小料
CaffeineBeverage.prototype.customerWantsCondiments = function () {
return true;
};
~~~
該函數在原型上擴展了所有的基礎步驟,以及主要步驟,沖泡和加小料步驟沒有實現,供具體飲料所對應的函數來實現,另外是否加小料(customerWantsCondiments )默認返回true,子函數重寫的時候可以重寫該值。
下面兩個函數分別是沖咖啡和沖茶所對應的函數:
~~~
// 沖咖啡
var Coffee = function () {
CaffeineBeverage.apply(this);
};
Coffee.prototype = new CaffeineBeverage();
Coffee.prototype.brew = function () {
console.log("從咖啡機想咖啡倒進去!");
};
Coffee.prototype.addCondiments = function () {
console.log("添加糖和牛奶");
};
Coffee.prototype.customerWantsCondiments = function () {
return confirm("你想添加糖和牛奶嗎?");
};
//沖茶葉
var Tea = function () {
CaffeineBeverage.apply(this);
};
Tea.prototype = new CaffeineBeverage();
Tea.prototype.brew = function () {
console.log("泡茶葉!");
};
Tea.prototype.addCondiments = function () {
console.log("添加檸檬!");
};
Tea.prototype.customerWantsCondiments = function () {
return confirm("你想添加檸檬嘛?");
};
~~~
另外使用confirm,可以讓用戶自己選擇加不加小料,很不錯,不是嘛?
## 總結
模板方法應用于下列情況:
1. 一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現
2. 各子類中公共的行為應被提取出來并集中到一個公共父類中的避免代碼重復,不同之處分離為新的操作,最后,用一個釣魚這些新操作的模板方法來替換這些不同的代碼
3. 控制子類擴展,模板方法只在特定點調用“hook”操作,這樣就允許在這些點進行擴展
和策略模式不同,模板方法使用繼承來改變算法的一部分,而策略模式使用委托來改變整個算法。
參考:https://github.com/tcorral/Design-Patterns-in-Javascript/blob/master/Template/withHook/index.html
- (1)編寫高質量JavaScript代碼的基本要點
- (2)揭秘命名函數表達式
- (3)全面解析Module模式
- (4)立即調用的函數表達式
- (5)強大的原型和原型鏈
- (6)S.O.L.I.D五大原則之單一職責SRP
- (7)S.O.L.I.D五大原則之開閉原則OCP
- (8)S.O.L.I.D五大原則之里氏替換原則LSP
- (9)根本沒有“JSON對象”這回事!
- (10)JavaScript核心(晉級高手必讀篇)
- (11)執行上下文(Execution Contexts)
- (12)變量對象(Variable Object)
- (13)This? Yes, this!
- (14)作用域鏈(Scope Chain)
- (15)函數(Functions)
- (16)閉包(Closures)
- (17)面向對象編程之一般理論
- (18)面向對象編程之ECMAScript實現
- (19)求值策略
- (20)《你真懂JavaScript嗎?》答案詳解
- (21)S.O.L.I.D五大原則之接口隔離原則ISP
- (22)S.O.L.I.D五大原則之依賴倒置原則DIP
- (23)JavaScript與DOM(上)——也適用于新手
- (24)JavaScript與DOM(下)
- (25)設計模式之單例模式
- (26)設計模式之構造函數模式
- (27)設計模式之建造者模式
- (28)設計模式之工廠模式
- (29)設計模式之裝飾者模式
- (30)設計模式之外觀模式
- (31)設計模式之代理模式
- (32)設計模式之觀察者模式
- (33)設計模式之策略模式
- (34)設計模式之命令模式
- (35)設計模式之迭代器模式
- (36)設計模式之中介者模式
- (37)設計模式之享元模式
- (38)設計模式之職責鏈模式
- (39)設計模式之適配器模式
- (40)設計模式之組合模式
- (41)設計模式之模板方法
- (42)設計模式之原型模式
- (43)設計模式之狀態模式
- (44)設計模式之橋接模式
- (45)代碼復用模式(避免篇)
- (46)代碼復用模式(推薦篇)
- (47)對象創建模式(上篇)
- (48)對象創建模式(下篇)
- (49)Function模式(上篇)
- (50)Function模式(下篇)
- (結局篇)