摘要:嗯,模板模式應(yīng)該是跟楊洋一樣帥,所以帶著這份愛慕,我們一起來看看它到底有沒有比楊洋還要帥模板方法模式是什么模板方法模式是一種只需使用繼承就可以實(shí)現(xiàn)的非常簡單的模式。模板方法模式由兩部分結(jié)構(gòu)組成,第一部分是抽象父類,第二部分是具體實(shí)現(xiàn)的子類。
JavaScript-模板方法模式
模板方法是什么鬼?模板模式又是什么鬼?? 聽說它很復(fù)雜,聽說它很難,我可不可以不學(xué)啊?。刷了一會兒微博,這幾天楊洋的新電影《三生三世十里桃花》上映了,不行,我要去看,雖然閨蜜說不好看,但是,去看楊洋也是可以的,嘻嘻嘻。 嗯,模板模式應(yīng)該是跟楊洋一樣帥,所以帶著這份愛慕,我們一起來看看它到底有沒有比楊洋還要帥??!
模板方法模式是什么?模板方法模式是一種只需使用繼承就可以實(shí)現(xiàn)的非常簡單的模式。這是它的一種定義,簡單嗎?不覺得。? ?
說到繼承,我們一定會能夠想到它肯定有父親,不然要怎么繼承。模板方法模式由兩部分結(jié)構(gòu)組成,第一部分是抽象父類,第二部分是具體實(shí)現(xiàn)的子類。完了,又出來一個(gè)概念,抽象類?別怕,我們一一來講解。在模板方法模式中,子類實(shí)現(xiàn)中的相同部分被上移到父類中,而將不同的部分留給子類來實(shí)現(xiàn)。
首先我們先來泡一杯咖啡,一般來說,泡咖啡的步驟通常如下:
1.先把水煮沸;
2.用沸水沖泡咖啡;
3.把咖啡倒進(jìn)杯子;
4.加糖和牛奶。
我們用es5來得到一杯香濃的咖啡吧:
var Coffee=function(){} Coffee.prototype.boilWater=function(){ console.log("水煮開了"); } Coffee.prototype.brewCoffeeGriends=function(){ console.log("用沸水沖泡咖啡"); } Coffee.prototype.pourInCup=function(){ console.log("把咖啡倒進(jìn)杯子"); } Coffee.prototype.addSugarAndMilk=function(){ console.log("加糖和牛奶"); } // 封裝 將實(shí)現(xiàn)的細(xì)節(jié)交給類的內(nèi)部 Coffee.prototype.init = function() { this.boilWater(); this.brewCoffeeGriends(); this.pourInCup(); this.addSugarAndMilk(); } var coffee=new Coffee(); coffee.init();
如我們所愿了,控制臺會輸出泡茶的流程,和我們寫下的一樣。
其實(shí)呢,泡茶的步驟跟泡咖啡的步驟相差不大,大致是這樣的:
1.把水煮沸;
2.用沸水浸泡茶葉;
3.把茶水倒進(jìn)杯子;
4.加檸檬。
來,咱用es6來泡茶:
class Tea{ constructor(){ } boilWater(){ console.log("把水燒開"); } steepTeaBag(){ console.log("浸泡茶葉"); } pourInCup(){ console.log("倒進(jìn)杯子"); } addLemon(){ console.log("加檸檬"); } init(){ this.boilWater(); this.steepTeaBag(); this.pourInCup(); this.addLemon(); } } var tea=new Tea(); tea.init();
又如我們所愿了,控制臺輸出了泡茶的流程。
思考啦!現(xiàn)在到了思考的時(shí)間,我們剛剛泡了一杯咖啡和一壺茶,有沒有覺得這兩個(gè)過程是大同小異的。我們能很容易的就找出他們的共同點(diǎn),不同點(diǎn)就是原料不同嘛,茶和咖啡,我們可以把他們抽象為"飲料"哇;泡的方式不同嘛,一個(gè)是沖泡,一個(gè)是浸泡,我們可以把這個(gè)行為抽象為"泡";加入的調(diào)料也不同咯,加糖和牛奶,加檸檬,它們也可以抽象為"調(diào)料"吖。
這么一分析,是不是很清楚了吖,我們整理一下就是:
1.把水煮沸;
2.用沸水沖泡飲料;
3.把飲料倒進(jìn)杯子;
4.加調(diào)料。
抽象類是不能被實(shí)例化的,一定是用來繼承的。繼承了抽象類的所有子類都將擁有跟抽象類一致的接口方法,抽象類的主要作用就是為它的子類定義這些公共接口。
通過上面分析,這里具體來說就是要把泡茶和泡咖啡的共同步驟共同點(diǎn)找出來,封裝到父類,也就是抽象類中,然后不同的步驟寫在子類中,也就是茶和咖啡中。抽象類既然不能被實(shí)例化,不怕啊,子類就是他的實(shí)例化。
來吧!泡飲料啦!var Beverage=function(){} Beverage.prototype.boilWater=function(){ console.log("把水煮沸"); } Beverage.prototype.brew=function(){}; Beverage.prototype.pourInCup=function(){}; Beverage.prototype.addCondiments=function(){}; // 抽象方法 Beverage.prototype.init=function(){ this.boilWater(); this.brew(); this.pourInCup(); this.addCondiments(); } var Coffee=function(){ // 將父類的構(gòu)造方法拿來執(zhí)行一下 Beverage.apply(this,arguments); // 就像es6的super執(zhí)行 執(zhí)行后this才會有對象的屬性 } Coffee.prototype=new Beverage(); var coffee=new Coffee(); coffee.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 tea=new Tea(); tea.init();
這里既泡了咖啡又泡了茶,是不是沒有之前那么繁瑣呢,這里的代碼可是很高級的呢。
這里用一個(gè)父類Beverage來表示Coffee和Tea,然后子類就是后面的Coffee和Tea啦,因?yàn)檫@里的Beverage是一個(gè)抽象的存在,需要子類來繼承它。泡飲品的流程,可以理解為一個(gè)模板模式 ,抽象類Beverage, 抽象方法init()在子類中實(shí)現(xiàn)。js的繼承是基于原型鏈的繼承,這里prototype就是類的原型鏈。這里由于coffee對象和tea對象的原型prototype上都沒有對應(yīng)的init(),所以請求會順著原型鏈,找到父類Beverage的init()。子類尋找對應(yīng)的屬性和方法的時(shí)候會順著原型鏈去查找,先找自己,沒有找到會順著去父類里面查找。
Beverage.prototype.init被稱為模板方法的原因是,該方法中封裝了子類的算法框架,它作為一個(gè)算法的模板,指導(dǎo)子類以何種順序去執(zhí)行哪些方法。
閉包也可以實(shí)現(xiàn)的喲,大家對閉包不太理解的可以參考我之前的文章:作用域閉包
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=Beverage({ brew:function(){ console.log("用沸水泡咖啡"); }, pourInCup:function(){ console.log("把咖啡倒進(jìn)杯子"); }, addCondiments:function(){ console.log("加糖和牛奶"); } }) var coffee=new Coffee(); coffee.init();
js 把抽象類改為配置類,param將成為Beverage函數(shù)里面的閉包函數(shù)的引用。Beverage是模板,把他變成一個(gè)可以配置的類把參數(shù)param傳進(jìn)來,就玩成了配置。這里的配置就是給Beverage傳參數(shù),也就是param。F對象規(guī)范了類的構(gòu)成(流程), ?里面的四個(gè)私有變量是閉包的。當(dāng)Beverage new 的時(shí)候會new 一個(gè)F, 然后就調(diào)用了閉包 ,四個(gè)私有變量也被調(diào)用。
父類里面的brew pourInCup addCondiments方法都是空的,所以子類必須重寫。父類里面的那三個(gè)方法是如果子類沒用重寫該方法,就會直接拋出一個(gè)異常那個(gè),程序在運(yùn)行時(shí)會得到一個(gè)錯(cuò)誤。
模板方法模式時(shí)一種典型的通過封裝變化提高系統(tǒng)擴(kuò)展性的設(shè)計(jì)模式。運(yùn)用了模板方法模式的程序中,子類方法種類和執(zhí)行順序都是不變的,但是子類的方法具體實(shí)現(xiàn)則是可變的。父類是個(gè)模板,子類可以添加,就增加了不同的功能。子類和父類之間也就是"堯舜禹"之間的關(guān)系,屬于同一類,沒有血緣關(guān)系。
哇,到這里帥哥就看完啦,是不是很帥,是不是很有意思,不行,我要去看我的楊洋了,拋棄我的楊洋。?
有建議或者覺得有錯(cuò)誤的地方可以指出來喲,帥哥要分享,學(xué)習(xí)也要分享的。共同進(jìn)步吧!?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/84647.html
摘要:模板方法模式定義定義抽象類并且聲明一些抽象基本方法供子類實(shí)現(xiàn)不同邏輯,同時(shí)在抽象類中定義具體方法把抽象基本方法封裝起來,這就是模板方法模式。 近日,ofo小黃車宣布入駐法國巴黎,正式進(jìn)入全球第20個(gè)國家,共享單車已然改變了我們的出行方式。就拿我自己來說,每當(dāng)下班出地鐵的第一件事,以光速鎖定一輛共享單車,百米沖刺的速度搶在別人之前占領(lǐng)它。 而大家都是重復(fù)著同樣的動(dòng)作,拿出手機(jī)開鎖、騎車、...
摘要:重構(gòu)時(shí),模板方法模式是一個(gè)經(jīng)常使用的模式,把相同的代碼抽取到父類中,然后通過鉤子函數(shù)詳見后面的擴(kuò)展示例約束其行為。 定義 Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.TemplateMethod lets subclasses redefine certai...
摘要:也是一些架構(gòu)師常用的模式。寫出方法,需要子類自己定義穿衣服需要子類自定義洗臉?biāo)⒀雷宇愖远x方法出門準(zhǔn)備工作需要子類自定義出門穿阿迪吊絲的衣服整理文件,找工作恩,這個(gè)模板,差不多能滿足正常人的需求。 所謂的模板就是一個(gè)重用一萬次都不會覺得有問題的代碼。 在es6中,提出了一個(gè) ``反引號的書寫方式--又叫做模板字符串.他最大的功能就是用來書寫模板html的.通常在js中使用模板是 T...
摘要:前言本系列文章主要根據(jù)設(shè)計(jì)模式與開發(fā)實(shí)踐整理而來,其中會加入了一些自己的思考。模板方法模式由兩部分結(jié)構(gòu)組成,第一部分是抽象父類,第二部分是具體的實(shí)現(xiàn)子類。 前言 本系列文章主要根據(jù)《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》整理而來,其中會加入了一些自己的思考。希望對大家有所幫助。 文章系列 js設(shè)計(jì)模式--單例模式 js設(shè)計(jì)模式--策略模式 js設(shè)計(jì)模式--代理模式 js設(shè)計(jì)模式--迭...
閱讀 1558·2021-11-18 10:02
閱讀 1728·2021-09-04 16:40
閱讀 3201·2021-09-01 10:48
閱讀 903·2019-08-30 15:55
閱讀 1883·2019-08-30 15:55
閱讀 1398·2019-08-30 13:05
閱讀 3041·2019-08-30 12:52
閱讀 1643·2019-08-30 11:24