深入理解JavaScript系列(41):設(shè)計(jì)模式之模板方法詳解
介紹
模板方法(TemplateMethod)定義了一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
模板方法是一種代碼復(fù)用的基本技術(shù),在類庫(kù)中尤為重要,因?yàn)樗麄兲崛×祟悗?kù)中的公共行為。模板方法導(dǎo)致一種反向的控制結(jié)構(gòu),這種結(jié)構(gòu)就是傳說(shuō)中的“好萊塢法則”,即“別找找我們,我們找你”,這指的是父類調(diào)用一個(gè)類的操作,而不是相反。具體體現(xiàn)是面向?qū)ο缶幊叹幊陶Z(yǔ)言里的抽象類(以及其中的抽象方法),以及繼承該抽象類(和抽象方法)的子類。
正文
舉個(gè)例子,泡茶和泡咖啡有同樣的步驟,比如燒開水(boilWater)、沖泡(brew)、倒在杯子里(pourOnCup),加小料(addCondiments)等等。但每種飲料沖泡的方法以及所加的小料不一樣,所以我們可以利用模板方法實(shí)現(xiàn)這個(gè)主要步驟。
首先先來(lái)定義抽象步驟:
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("該方法必須重寫!");
};
// 默認(rèn)加上小料
CaffeineBeverage.prototype.customerWantsCondiments = function () {
return true;
};
該函數(shù)在原型上擴(kuò)展了所有的基礎(chǔ)步驟,以及主要步驟,沖泡和加小料步驟沒(méi)有實(shí)現(xiàn),供具體飲料所對(duì)應(yīng)的函數(shù)來(lái)實(shí)現(xiàn),另外是否加小料(customerWantsCondiments )默認(rèn)返回true,子函數(shù)重寫的時(shí)候可以重寫該值。
下面兩個(gè)函數(shù)分別是沖咖啡和沖茶所對(duì)應(yīng)的函數(shù):
// 沖咖啡
var Coffee = function () {
CaffeineBeverage.apply(this);
};
Coffee.prototype = new CaffeineBeverage();
Coffee.prototype.brew = function () {
console.log("從咖啡機(jī)想咖啡倒進(jìn)去!");
};
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,可以讓用戶自己選擇加不加小料,很不錯(cuò),不是嘛?
總結(jié)
模板方法應(yīng)用于下列情況:
1.一次性實(shí)現(xiàn)一個(gè)算法的不變的部分,并將可變的行為留給子類來(lái)實(shí)現(xiàn)
2.各子類中公共的行為應(yīng)被提取出來(lái)并集中到一個(gè)公共父類中的避免代碼重復(fù),不同之處分離為新的操作,最后,用一個(gè)釣魚這些新操作的模板方法來(lái)替換這些不同的代碼
3.控制子類擴(kuò)展,模板方法只在特定點(diǎn)調(diào)用“hook”操作,這樣就允許在這些點(diǎn)進(jìn)行擴(kuò)展
和策略模式不同,模板方法使用繼承來(lái)改變算法的一部分,而策略模式使用委托來(lái)改變整個(gè)算法。
相關(guān)文章
jquery中prop()方法和attr()方法的區(qū)別淺析
官方例舉的例子感覺(jué)和attr()差不多,也不知道有什么區(qū)別,既然有了prop()這個(gè)新方法,不可能沒(méi)用吧,那什么時(shí)候該用attr(),什么時(shí)候該用prop()呢2013-09-09JavaScript String 對(duì)象常用方法詳解
下面小編就為大家?guī)?lái)一篇JavaScript String 對(duì)象常用方法詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05javascript操作html控件實(shí)例(javascript添加html)
幾乎HTML所有標(biāo)記都可以說(shuō)是HTML的控件,如select, input, div, table等。html標(biāo)簽便捷的操作,深受大家的喜歡。如何使用javascript來(lái)操作HTML控件,下面我介紹下比較麻煩的幾個(gè)控件2013-12-12Javascript Throttle & Debounce應(yīng)用介紹
Throttle:無(wú)視一定時(shí)間內(nèi)所有的調(diào)用Debounce:一定間隔內(nèi)沒(méi)有調(diào)用時(shí),接下來(lái)將為大家介紹下Throttle & Debounce的應(yīng)用,感興趣的朋友可以參考下哈2013-03-03使用HTML+CSS+JS制作簡(jiǎn)單的網(wǎng)頁(yè)菜單界面
這篇文章主要介紹了使用HTML+CSS+JS制作簡(jiǎn)單的網(wǎng)頁(yè)菜單界面,這個(gè)ABROAD項(xiàng)目所使用的JavaScript部分代碼非常簡(jiǎn)單,需要的朋友可以參考下2015-07-07JavaScript中對(duì)JSON對(duì)象的基本操作示例
JSON格式本就發(fā)自于JavaScript中的對(duì)象和數(shù)組,所以js操作起來(lái)自然也是最為簡(jiǎn)單原始,接下來(lái)我們就來(lái)看一些常用的JavaScript中對(duì)JSON對(duì)象的基本操作示例2016-05-05輕松學(xué)習(xí)JavaScript函數(shù)中的 Rest 參數(shù)
ES6 引入 rest 參數(shù)用于獲取函數(shù)的多余參數(shù),這樣就不需要使用arguments對(duì)象了。rest 參數(shù)搭配的變量是一個(gè)數(shù)組,該變量將多余的參數(shù)放入數(shù)組中。下面我們來(lái)詳細(xì)了解一下吧2019-05-05