JavaScript設(shè)計(jì)模式-模板方法模式

概念

??模板方法模式是一種只需使用繼承就可以實(shí)現(xiàn)的非常簡單的模式术吗。模板方法模式由兩部分結(jié)構(gòu)組成擒滑,第一部分是抽象父類骂蓖,第二部分是具體的實(shí)現(xiàn)子類积瞒。通常在抽象父類中封裝了子類的算法框架,包括實(shí)現(xiàn)一些公共方法以及封裝子類中所有方法的執(zhí)行順序登下。子類通過繼承這個抽象類茫孔,也繼承了整個算法結(jié)構(gòu),并且可以選擇重寫父類的方法被芳。
??假如有一些平行的子類缰贝,各個子類之間有一些相同的行為,也有一些不同的行為畔濒。如果相同和不同的行為都混合在各個子類的實(shí)現(xiàn)中剩晴,說明這些相同的行為會在各個子類中重復(fù)出現(xiàn)。但實(shí)際上侵状,相同的行為可以被搬移到另外一個單一的地方赞弥,模板方法模式就是為解決這個問題而生的。在模板方法模式中趣兄,子類實(shí)現(xiàn)中的相同部分被上移到父類中绽左,而將不同的部分留在子類來實(shí)現(xiàn)。這也很好地體現(xiàn)了泛化的思想艇潭。

應(yīng)用

抽象類

??模板方法模式是一種嚴(yán)重依賴抽象類的設(shè)計(jì)模式拼窥。JS在語言層面并沒有提供對抽象類的支持,故下面代碼用JS的超集TS編寫蹋凝。
??我們先來看看抽象類在正統(tǒng)的面向?qū)ο缶幊陶Z言中的作用鲁纠。在Java中,類分為兩種鳍寂,一種為具體類房交,另一種為抽象類。具體類可以被實(shí)例化伐割,抽象類不能被實(shí)例化候味。要了解抽象類不能被實(shí)例化的原因刃唤,可以思考“飲料”這個抽象類。
  想象這樣一個場景:口渴了去便利店想買一瓶飲料白群,不能直接跟店員說:“來一瓶飲料”尚胞。如果這樣說了,那么店員接下來肯定會問:“要什么飲料帜慢?”飲料只是一個抽象名詞笼裳,只有當(dāng)真正明確了的飲料類型之后,才能得到一杯咖啡粱玲、茶或者可樂躬柬。
  由于抽象類不能被實(shí)例化,如果有人編寫了一個抽象類抽减,那么這個抽象類一定是用來被某些具體類繼承的允青。抽象類表示一種契約。繼承了這個抽象類的所有子類都將擁有跟抽象類一致的接口方法卵沉,抽象類的主要作用就是為它的子類定義這些公共接口颠锉。如果在子類中刪掉了這些方法中的某一個,那么將不能通過編譯器的檢查史汗。
??抽象方法被聲明在抽象類中琼掠,抽象方法并沒有具體的實(shí)現(xiàn)過程,是一些“啞”方法停撞。除了抽象方法之外瓷蛙,如果每個子類中都有一些同樣的具體實(shí)現(xiàn)方法,那這些方法也可以選擇放在抽象類中戈毒,這可以節(jié)省代碼以達(dá)到復(fù)用的效果速挑,這些方法叫作具體方法。
??咖啡與茶是一個經(jīng)典的例子副硅,經(jīng)常用來講解模板方法模式姥宝,這個例子的原型來自《HeadFirst設(shè)計(jì)模式》。下面用TS模板方法模式來實(shí)現(xiàn)這個例子恐疲。

public abstract class Beverage{    //飲料抽象類
    init():void{    //模板方法
        this.boilWater()
        this.brew()
        this.pourInCup()
        this.addCondiments()
    }

    boilWater():void{    //具體方法
       console.log("把水煮沸")
    }

    abstract  brew():void    //抽象方法brew
    abstract  addCondiments():void        //抽象方法addCondiments
    abstract pourInCup():void    //抽象方法pourInCup
}

public class Coffee extends Beverage{    //Coffee類
     brew():void{    //子類中重寫brew方法
        console.log("用沸水沖泡咖啡")
    }
     pourInCup():void{    //子類中重寫pourInCup方法
        console.log("把咖啡倒進(jìn)杯子")
    }
     addCondiments():void{    //子類中重寫addCondiments方法
        console.log("加糖和牛奶")
    }
}

public class Tea extends Beverage{    //Tea類
    brew():void{    //子類中重寫brew方法
        console.log("用沸水浸泡茶葉")
    }

    pourInCup():void{    //子類中重寫pourInCup方法
        console.log("把茶倒進(jìn)杯子")
    }

    addCondiments():void{    //子類中重寫addCondiments方法
        console.log("加檸檬")
    }
}
Beverage coffee = new Coffee()    // 創(chuàng)建coffee對象
coffee.init()     // 把水煮沸腊满、用沸水沖泡咖啡、把咖啡倒進(jìn)杯子培己、加糖和牛奶
Beverage tea = new Tea()    // 創(chuàng)建tea對象
tea.init()       // 把水煮沸碳蛋、用沸水浸泡茶葉、把茶倒進(jìn)杯子省咨、加檸檬

鉤子方法

??放置鉤子是隔離變化的一種常見手段肃弟。在父類中容易變化的地方放置鉤子,鉤子可以有一個默認(rèn)的實(shí)現(xiàn),究竟要不要“掛鉤”笤受,這由子類自行決定穷缤。鉤子方法的返回結(jié)果決定了模板方法后面部分的執(zhí)行步驟,也就是程序接下來的走向箩兽,這樣一來津肛,程序就擁有了變化的可能。

 class Beverage {
    init(): void {
        this.boilWater()
        this.brew()
        this.pourInCup()
        if (this.customerWantsCondiments() ){ // 如果掛鉤返回true汗贫,則需要調(diào)料
            this.addCondiments();
        }
    }

    boilWater(): void {
        console.log("把水煮沸")
    }

    brew() {
        throw new Error('子類必須重寫brew方法')
    }

    pourInCup() {
        throw new Error('子類必須重寫pourInCup方法')
    }

    customerWantsCondiments ():boolean {
        return true
     }
     addCondiments() {
         throw new Error('子類必須重寫addCondiments方法')
     }
}

 class Coffee extends Beverage {
    brew() {
        console.log("用沸水沖泡咖啡")
    }

    pourInCup(){
        console.log("把咖啡倒進(jìn)杯子")
    }

     customerWantsCondiments() {
         return window.confirm( '請問需要調(diào)料嗎身坐?' );
    }
     addCondiments() {
         console.log( '加糖和牛奶' );
     }
}

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

??下面引入一個新的設(shè)計(jì)原則——“好萊塢原則”。好萊塢無疑是演員的天堂落包,但好萊塢也有很多找不到工作的新人演員部蛇,許多新人演員在好萊塢把簡歷遞給演藝公司之后就只有回家等待電話。有時候該演員等得不耐煩了咐蝇,給演藝公司打電話詢問情況涯鲁,演藝公司往往這樣回答:“不要來找我,我會給你打電話嘹害〈楦停”
  在設(shè)計(jì)中吮便,這樣的規(guī)則就稱為好萊塢原則笔呀。在這一原則的指導(dǎo)下,允許底層組件將自己掛鉤到高層組件中髓需,而高層組件會決定什么時候许师、以何種方式去使用這些底層組件,高層組件對待底層組件的方式僚匆,跟演藝公司對待新人演員一樣微渠,都是“別調(diào)用我們,我們會調(diào)用你”
  模板方法模式是好萊塢原則的一個典型使用場景咧擂,它與好萊塢原則的聯(lián)系非常明顯逞盆,用模板方法模式編寫一個程序時,就意味著子類放棄了對自己的控制權(quán)松申,而是改為父類通知子類云芦,哪些方法應(yīng)該在什么時候被調(diào)用。作為子類贸桶,只負(fù)責(zé)提供一些設(shè)計(jì)上的細(xì)節(jié)舅逸。

小結(jié)

??模板方法模式是一種典型的通過封裝變化提高系統(tǒng)擴(kuò)展性的設(shè)計(jì)模式。在傳統(tǒng)的面向?qū)ο笳Z言中皇筛,一個運(yùn)用了模板方法模式的程序中琉历,子類的方法種類和執(zhí)行順序都是不變的,所以把這部分邏輯抽象到父類的模板方法里面。而子類的方法具體怎么實(shí)現(xiàn)則是可變的旗笔,于是把這部分變化的邏輯封裝到子類中彪置。通過增加新的子類,便能給系統(tǒng)增加新的功能换团,并不需要改動抽象父類以及其他子類悉稠,這也是符合開放——封閉原則的。

參考文獻(xiàn)

《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末艘包,一起剝皮案震驚了整個濱河市的猛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌想虎,老刑警劉巖卦尊,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舌厨,居然都是意外死亡岂却,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門裙椭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躏哩,“玉大人,你說我怎么就攤上這事揉燃∩ǔ撸” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵炊汤,是天一觀的道長正驻。 經(jīng)常有香客問我,道長抢腐,這世上最難降的妖魔是什么姑曙? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮迈倍,結(jié)果婚禮上伤靠,老公的妹妹穿的比我還像新娘。我一直安慰自己啼染,他們只是感情好宴合,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著提完,像睡著了一般形纺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徒欣,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天逐样,我揣著相機(jī)與錄音,去河邊找鬼。 笑死脂新,一個胖子當(dāng)著我的面吹牛挪捕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播争便,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼级零,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滞乙?” 一聲冷哼從身側(cè)響起奏纪,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斩启,沒想到半個月后序调,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兔簇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年发绢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垄琐。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡边酒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狸窘,到底是詐尸還是另有隱情墩朦,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布朦前,位于F島的核電站介杆,受9級特大地震影響鹃操,放射性物質(zhì)發(fā)生泄漏韭寸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一荆隘、第九天 我趴在偏房一處隱蔽的房頂上張望恩伺。 院中可真熱鬧,春花似錦椰拒、人聲如沸晶渠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褒脯。三九已至,卻和暖如春缆毁,著一層夾襖步出監(jiān)牢的瞬間番川,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颁督,地道東北人践啄。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像沉御,于是被迫代替她去往敵國和親屿讽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

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