javascript設(shè)計模式七:模板方法模式

模板方法模式,是一種典型的通過封裝變化提高系統(tǒng)擴(kuò)展性的設(shè)計模式。在傳統(tǒng)的面向?qū)ο笳Z言中榔袋,一個運用了模板方法模式的程序中烈和,子類的方法種類和執(zhí)行順序都是基本不變的爱只,所以把這部分邏輯抽象到父類的模板方法中。而子類的方法具體怎么實現(xiàn)則是可變的招刹,于是我們把這部分變化的邏輯封裝到子類中恬试。通過增加新的子類,就能給系統(tǒng)增加新的功能疯暑,并不需要改動抽象父類以及其他子類训柴,這符合開放-封閉原則。

定義抽象類妇拯,父類

模板方法模式

Beverage是模板類幻馁,Beverage.prototype.init是模板方法洗鸵,它被稱為模板方法的原因是它內(nèi)部封裝了子類的算法框架,它作為一個算法的模板仗嗦,指導(dǎo)子類以何種順序去執(zhí)行方法

var Beverage = function(){}

Beverage.prototype.boilWater = function(){
    console.log('把水煮沸');
}

Beverage.prototype.brew = function(){
    throw new Error('子類必須重寫brew方法')     
}      //空方法膘滨,由子類重寫,如果子類不重寫該方法稀拐,會直接拋出異常提醒

Beverage.prototype.pourInCup = function(){
    throw new Error('子類必須重寫pourInCup方法')
}     //空方法火邓,由子類重寫,如果子類不重寫該方法钩蚊,會直接拋出異常提醒

Beverage.prototype.addCondiments = function(){
    throw new Error('子類必須重寫addCondiments方法')
}     //空方法贡翘,由子類重寫,如果子類不重寫該方法砰逻,會直接拋出異常提醒

Beverage.prototype.init = function(){   //初始化方法    
    this.boilWater()
    this.brew()
    this.pourInCup()
    this.addCondiments()
}

//子類繼承父類
//咖啡類鸣驱,泡咖啡
var Coffee = function(){}

Coffee.prototype = new Beverage()

Coffee.prototype.brew = function(){
    console.log('用沸水沖泡咖啡');
}

Coffee.prototype.pourInCup = function(){
    console.log('把咖啡倒進(jìn)杯子');
}

Coffee.prototype.addCondiments = function(){
    console.log('加糖和牛奶');
}

var oneCoffee = new Coffee()

oneCoffee.init()

//子類
//茶類,泡茶
var Tea = function(){}
Tea.prototype = new Beverage()

Tea.prototype.brew = function(){
    console.log('用沸水浸泡茶葉');
}

Tea.prototype.pourInCup = function(){
    console.log('把茶倒進(jìn)杯子');
}

Tea.prototype.addCondiments = function(){
    console.log('加檸檬');
}

var oneTea = new Tea()

oneTea.init()

父類中鉤子方法

在之前的Beverage類中蝠咆,模板方法init已經(jīng)規(guī)定好飲料沖泡的順序踊东,大部分情況是合適的,但如果有的飲料不加調(diào)料呢刚操?所以需要有個合適的方法來使得子類不受父類模板方法的約束闸翅。

鉤子方法(hook)可以用來解決這個問題,放置鉤子是隔離變化的一種常見手段菊霜。在父類中容易變化的地方放置鉤子坚冀,鉤子可以有一個默認(rèn)的實現(xiàn),究竟要不要“掛鉤”鉴逞,由子類自行決定记某。

鉤子方法的返回結(jié)果決定了模板方法后面部分的執(zhí)行步驟,也就是程序接下來的走向构捡,如此液南,程序就擁有變化的可能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
<script>
var Beverage = function(){}

Beverage.prototype.boilWater = function(){
    console.log('把水煮沸');
}

Beverage.prototype.brew = function(){
    throw new Error('子類必須重寫brew方法')     
}      //空方法勾徽,由子類重寫滑凉,如果子類不重寫該方法,會直接拋出異常提醒

Beverage.prototype.pourInCup = function(){
    throw new Error('子類必須重寫pourInCup方法')
}     //空方法喘帚,由子類重寫畅姊,如果子類不重寫該方法,會直接拋出異常提醒

Beverage.prototype.addCondiments = function(){
    throw new Error('子類必須重寫addCondiments方法')
}     //空方法吹由,由子類重寫若未,如果子類不重寫該方法,會直接拋出異常提醒

Beverage.prototype.customerWantsCondiments = function(){    //鉤子方法溉知,
    return true;    //默認(rèn)需要調(diào)料
}

Beverage.prototype.init = function(){   //初始化方法    
    this.boilWater()
    this.brew()
    this.pourInCup()
    if(this.customerWantsCondiments()){   //在模板方法中陨瘩,默認(rèn)是需要調(diào)料的
        this.addCondiments()
    }
    
}

//子類
var CoffeeWithHooK = function(){}

CoffeeWithHooK.prototype = new Beverage()

CoffeeWithHooK.prototype.brew = function(){
    console.log('用沸水沖泡咖啡');
}

CoffeeWithHooK.prototype.pourInCup = function(){
    console.log('把咖啡倒進(jìn)杯子');
}

CoffeeWithHooK.prototype.addCondiments = function(){
    console.log('加糖和牛奶');
}

CoffeeWithHooK.prototype.customerWantsCondiments = function(){
    return window.confirm('您需要加調(diào)料么?')
}

var oneCoffeeWithHooK = new CoffeeWithHooK()

oneCoffeeWithHooK.init()

</script>
</html>

在js中腕够,基于繼承的應(yīng)用場景其實并不多,因為有更好的選擇舌劳,模板方法模式使用高階函數(shù)的寫法會更為優(yōu)雅帚湘。

var Beverage = function(param){
    var boilWater = function(){
        console.log('把水煮沸');
    }

    var brew = param.brew || function(){
        throw new Error('必須傳遞brew方法')
    }

    var pourInCup = param.pourInCup || function(){
        throw new Error('必須傳遞pourInCup方法')
    }

    var addCondiments = param.addCondiments || function(){
        throw new Error('必須傳遞addCondiments方法')
    }

    var F = function(){}

    F.prototype.init = function(){
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    return F;
}

var Coffee = new Beverage({
    brew: function(){
        console.log('用沸水沖泡咖啡');
    },
    pourInCup: function(){
        console.log('把咖啡倒進(jìn)杯子');
    },
    addCondiments: function(){
        console.log('加糖和牛奶');
    }
})

var Tea = new Beverage({
    brew: function(){
        console.log('用沸水浸泡茶葉');
    },
    pourInCup: function(){
        console.log('把茶倒進(jìn)杯子');
    },
    addCondiments: function(){
        console.log('加檸檬');
    }
})

var coffee = new Coffee()
coffee.init()

var tea = new Tea()
tea.init()

//把brew、pourInCup甚淡、addCondiments依次傳入Beverage函數(shù)中大诸,Beverage函數(shù)被調(diào)用之后返回構(gòu)造器F。F中包含模板方法 F.prototype.init贯卦,跟繼承得到的結(jié)果一樣资柔,該模板方法封裝了子類的算法結(jié)構(gòu)。

//在js中撵割,基于繼承的應(yīng)用場景其實并不多贿堰,因為有更好的選擇,使用高階函數(shù)的寫法會更為優(yōu)雅啡彬。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羹与,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子庶灿,更是在濱河造成了極大的恐慌纵搁,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件往踢,死亡現(xiàn)場離奇詭異腾誉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)峻呕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門利职,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人山上,你說我怎么就攤上這事眼耀∮⒅В” “怎么了佩憾?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長干花。 經(jīng)常有香客問我妄帘,道長,這世上最難降的妖魔是什么池凄? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任抡驼,我火速辦了婚禮,結(jié)果婚禮上肿仑,老公的妹妹穿的比我還像新娘致盟。我一直安慰自己碎税,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布馏锡。 她就那樣靜靜地躺著雷蹂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杯道。 梳的紋絲不亂的頭發(fā)上匪煌,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音党巾,去河邊找鬼萎庭。 笑死,一個胖子當(dāng)著我的面吹牛齿拂,可吹牛的內(nèi)容都是我干的驳规。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼署海,長吁一口氣:“原來是場噩夢啊……” “哼达舒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叹侄,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤巩搏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后趾代,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贯底,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年撒强,在試婚紗的時候發(fā)現(xiàn)自己被綠了禽捆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡飘哨,死狀恐怖胚想,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芽隆,我是刑警寧澤浊服,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站胚吁,受9級特大地震影響牙躺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腕扶,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一孽拷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧半抱,春花似錦脓恕、人聲如沸膜宋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽激蹲。三九已至,卻和暖如春江掩,著一層夾襖步出監(jiān)牢的瞬間学辱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工环形, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留策泣,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓抬吟,卻偏偏與公主長得像萨咕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子火本,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 靜待花開 初春的天氣危队,晚上依然是寒風(fēng)凜冽,低年級的學(xué)生們還是堅持在上晚自習(xí)钙畔,我很早便等候在學(xué)校門口茫陆,不停的...
    橙子的時光閱讀 201評論 2 1
  • 這一年,我大四畢業(yè)擎析。 這一天簿盅,我在浙江金華。 這一刻揍魂,我在懷念我懷念的人和事...
    酒挺好聽故事挺好喝閱讀 352評論 2 3