javascript
JavaScript 设计模式 : 巧用'工厂模式'和'创建者'模式
我為什么把他們兩個(gè)放在一起講?我覺得這兩個(gè)設(shè)計(jì)模式有相似之處,有時(shí)候會(huì)一個(gè)設(shè)計(jì)模式不能滿足你的需求而采用另一種設(shè)計(jì)模式。基于這點(diǎn)考慮,而且為了大家更好地理解,我放到了一起,加深大家的印象,活學(xué)活用。
[這里我為了能更好的體現(xiàn)下設(shè)計(jì)模式與JS本體語言的結(jié)合,我用了一點(diǎn)繼承關(guān)系. 有的同學(xué)都不知道JS能繼承,就算大家不懂繼承也希望大家能看下去,弄懂它!] 復(fù)制代碼本文擴(kuò)展
掘金有個(gè)文章繼承還是蠻透徹的 JS原型鏈與繼承別再被問倒了
工廠模式
- 創(chuàng)建對(duì)象跟對(duì)不同需求進(jìn)行不同的實(shí)例化
在我們Team協(xié)作開發(fā)過程當(dāng)中,不同于我們寫個(gè)人項(xiàng)目,對(duì)全局變量的限制很大,我們要盡量少的使用全局變量,對(duì)于一類對(duì)象在不同需求上的不同使用,甚至將一些有些類似的方法抽象化,可以用工廠模式來負(fù)責(zé)創(chuàng)建這些對(duì)象,調(diào)用者可以使用一部分資源也可以在基礎(chǔ)上私人訂制一套資源。
就拿昨天入群的小伙伴舉個(gè)栗子:他設(shè)計(jì)一個(gè)網(wǎng)頁播放器有四個(gè)按鈕:
我們不討論他的實(shí)現(xiàn)方式,我們按照工廠模式來簡單創(chuàng)建一個(gè)吧!
function wangyiMusicAction(action){var o = new Object;o.vender = '網(wǎng)易云音樂';o.playingMusic = 'see you again'switch (action){case 'last':o.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}breakcase 'next':o.information = {currentMusic:'一人我編程累',status:'200|404',message:'下一曲'}breakcase 'play':o.information = {currentMusic:'see you again',status:'200|500',message:'播放'}breakcase 'mute':o.information = {currentMusic:'see you again',status:'200|500',message:'靜音'}break}return o;} var music = wangyiMusicAction('next') console.log('音樂提供商 : '+music.vender); console.log('正在播放 : '+music.playingMusic); console.log('執(zhí)行動(dòng)作 : ' +music.information.message); console.log('接口狀態(tài) : ' +music.information.status); console.log('執(zhí)行動(dòng)作后歌曲 : ' +music.information.currentMusic);----------執(zhí)行結(jié)果--------音樂提供商 : 網(wǎng)易云音樂 正在播放 : see you again 執(zhí)行動(dòng)作 : 下一曲 接口狀態(tài) : 200|404 執(zhí)行動(dòng)作后歌曲 : 一人我編程累 復(fù)制代碼這其實(shí)使我們經(jīng)常使用的,不過這是面向過程的,不太符合我們的設(shè)計(jì)模式。我們用上篇學(xué)到的模式:對(duì)象
我們可以修改一下:
var WangyiMusicAction = function(action){this.vender = '網(wǎng)易云音樂';this.playingMusic = 'see you again'}WangyiMusicAction.prototype = {last : function() {this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}},next : function() {this.information = {currentMusic:'一人我編程累',status:'200|404',message:'下一曲'}},play : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}},mute : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'靜音'}}}var music = new WangyiMusicAction() music.next(); //執(zhí)行下一曲動(dòng)作 console.log('音樂提供商 : '+music.vender); console.log('正在播放 : '+music.playingMusic); console.log('執(zhí)行動(dòng)作 : ' +music.information.message); console.log('接口狀態(tài) : ' +music.information.status); console.log('執(zhí)行動(dòng)作后歌曲 : ' +music.information.currentMusic); 音樂提供商 : 網(wǎng)易云音樂 正在播放 : see you again 執(zhí)行動(dòng)作 : 下一曲 接口狀態(tài) : 200|400----------執(zhí)行結(jié)果--------執(zhí)行動(dòng)作后歌曲 : 一人我編程累復(fù)制代碼這樣就算是面向?qū)ο蟮牧?#xff0c;雖然達(dá)到目的,但是上面所說的,但是這算是Music的網(wǎng)易云音樂實(shí)現(xiàn)版本、總不能再來一個(gè)QQMusic、XiaMiMusic吧?我們建立一個(gè)Factory工廠來管理所有的音樂:
var WangyiMusicAction = function(action){this.vender = '網(wǎng)易云音樂';this.playingMusic = 'see you again'}//為網(wǎng)易音樂提供共有方法 WangyiMusicAction.prototype = {last : function() {this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}},next : function() {this.information = {currentMusic:'一人我編程累',status:'200|404',message:'下一曲'}},play : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}},mute : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'靜音'}}}var QQMusicAction = function(action){this.vender = 'QQ音樂';this.playingMusic = '其實(shí)我不low'}//為QQ音樂提供共有方法 QQMusicAction.prototype = {last : function() {this.information = {currentMusic:'Ich will',status:'200|404',message:'上一曲'}},next : function() {this.information = {currentMusic:'網(wǎng)易才low',status:'200|404',message:'下一曲'}},play : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}},mute : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'靜音'}}} //音樂工廠 var MusicFactory = function(type){switch (type){case 'qq':return new QQMusicAction();case 'wangyi':return new WangyiMusicAction()} }var music = new MusicFactory('qq') music.next(); //執(zhí)行下一曲動(dòng)作 console.log('音樂提供商 : '+music.vender); console.log('正在播放 : '+music.playingMusic); console.log('執(zhí)行動(dòng)作 : ' +music.information.message); console.log('接口狀態(tài) : ' +music.information.status); console.log('執(zhí)行動(dòng)作后歌曲 : ' +music.information.currentMusic);----------執(zhí)行結(jié)果--------音樂提供商 : QQ音樂 正在播放 : 其實(shí)我不low 執(zhí)行動(dòng)作 : 下一曲 接口狀態(tài) : 200|404 執(zhí)行動(dòng)作后歌曲 : 網(wǎng)易才low復(fù)制代碼這樣調(diào)用者需要用音樂接口,只需要記住MusicFactory就可以了,MusicFactory就像一個(gè)大工廠,對(duì)于music可以返回他要的一切。
好,我們回過頭來看一下:
第一種方法:是創(chuàng)建一個(gè)新的對(duì)象 o 對(duì)他來增強(qiáng) 屬性 的功能來實(shí)現(xiàn)的. 第二種方法:是實(shí)例化對(duì)象來創(chuàng)建的。 第二種方法:如果他們繼承同一個(gè)父類 BaseMusic 那么他們父類的原型方法是可以和它們公用的! 第一種方法:我們內(nèi)部 new 了一個(gè)新的個(gè)體,就不能與父類共用了.
具體哪種還是看你需求的,不過我更傾向第二種,因?yàn)樗麛U(kuò)展性高,需求多的時(shí)候我們甚至可以將通用的抽離出來放到父類BaseMusic中。
在下面的繼承中我運(yùn)用了類式繼承
ps:(大家可以看看構(gòu)造函數(shù)繼承和組合繼承鏈接在最下面) 復(fù)制代碼 //基類(父類)music方法 var BaseMusic = function(){this.playingMusic = 'see you again' } //實(shí)現(xiàn)通用方法 BaseMusic.prototype = {last : function() {this.information = {status:'200|404',message:'上一曲'}},next : function() {this.information = {currentMusic:'一人我編程累',status:'200|404',message:'下一曲'}},play : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'播放'}},mute : function() {this.information = {currentMusic:'see you again',status:'200|500',message:'靜音'}} } //網(wǎng)易云的不同于父類的構(gòu)造方法 var WangyiMusicAction = function(action){this.vender = '網(wǎng)易云音樂';} //這里通過prototype實(shí)現(xiàn)類繼承 WangyiMusicAction.prototype = new BaseMusic();//這些動(dòng)作我都放在基類了,達(dá)到代碼復(fù)用的目的//QQ var QQMusicAction = function(action){this.vender = 'QQ音樂';this.playingMusic = '其實(shí)我不low'} QQMusicAction.prototype = new BaseMusic() //這些動(dòng)作我都放在基類了,達(dá)到代碼復(fù)用的目的//音樂工廠 var MusicFactory = function(type){switch (type){case 'qq':return new QQMusicAction();case 'wangyi':return new WangyiMusicAction()} }var music = new MusicFactory('wangyi') music.next(); //執(zhí)行下一曲動(dòng)作 console.log('音樂提供商 : '+music.vender); console.log('正在播放 : '+music.playingMusic); console.log('執(zhí)行動(dòng)作 : ' +music.information.message); console.log('接口狀態(tài) : ' +music.information.status); console.log('執(zhí)行動(dòng)作后歌曲 : ' +music.information.currentMusic);----------執(zhí)行結(jié)果--------音樂提供商 : 網(wǎng)易云音樂 正在播放 : see you again 執(zhí)行動(dòng)作 : 下一曲 接口狀態(tài) : 200|404 執(zhí)行動(dòng)作后歌曲 : 一人我編程累 復(fù)制代碼這樣看起來是不是更好、更簡潔呢?
創(chuàng)建者模式
- 工廠模式職責(zé):我不管你想干啥,我只返回給你一個(gè)你想要的對(duì)象
- 創(chuàng)建者模式職責(zé):主要針對(duì)復(fù)雜業(yè)務(wù)的解耦,算是工廠的一種拆解、拼接。我可以將你的需求分解多個(gè)對(duì)象創(chuàng)建,更關(guān)心的是創(chuàng)建對(duì)象的過程。
不復(fù)雜不能突顯出他的魅力,舉個(gè)稍微復(fù)雜栗子:
我們公司是賣車的,用戶下單要買車,這個(gè)車呢:
品牌:邁巴赫、林肯、賓利、特斯拉[如果不選品牌,默認(rèn)特斯拉] 顏色:赤橙黃綠青藍(lán)紫...[如果不選顏色,默認(rèn)黃色] 動(dòng)力:燃油、電力、混合動(dòng)力[如果不選動(dòng)力,默認(rèn)電力] 購買人的一些備注信息[購買人可能會(huì)修改備注需要提供方法] 針對(duì)購買人選擇的車型返回對(duì)車型的簡單描述[描述可以修改]復(fù)制代碼最終根據(jù)用戶選擇來生成一個(gè)訂單: 想下這用工廠模式是不是要寫很多的if else來返回這么一個(gè)Car的對(duì)象呢?
我們先將 車 購買人的動(dòng)作 反饋 分解為三個(gè)對(duì)象再在最后進(jìn)行拼接 :
//創(chuàng)建一個(gè)汽車 var Car = function(param){this.color = param && param.color || 'yellow';this.brand = param && param.brand || 'Tesla';this.power = param && param.power || 'electric'; } //提供原型方法 Car.prototype = {getColor : function () {return this.color;},getBrand : function () {return this.brand;},getPower : function () {return this.power;} }//創(chuàng)建一個(gè)反饋 var FeedBack = function(brand){var that = this;(function(brand,that){switch (brand){case 'Tesla':// that.brand = brand;that.information = '特斯拉是好車'breakcase 'Rolls' :that.information = '勞斯來時(shí)是好車'}})(brand,that) }FeedBack.prototype.changeBrand = function (information) {this.information = information; }//創(chuàng)建一個(gè)顧客 var Client = function(name,message){this.name = name;this.message = message || '無留言'; } //顧客修改備注 Client.prototype.changeMessage = function(message){this.message = message; } //然后重點(diǎn)在這里!我們?cè)谶@里將我們分解的拼接起來。 var Order = function(name){var object = new Car();object.client = new Client(name);object.feedBack = new FeedBack(object.brand);return object; }var orderCar = new Order('Vendar-MH'); console.log('The' + orderCar.client.name + '先生、下單一輛' + orderCar.color + '的' + orderCar.brand +' 留言內(nèi)容 : ' +orderCar.client.message ); orderCar.client.changeMessage('請(qǐng)馬上電話聯(lián)系我') console.log('The' + orderCar.client.name + '先生、下單一輛' + orderCar.color + '的' + orderCar.brand +' 留言內(nèi)容 : ' +orderCar.client.message );----------執(zhí)行結(jié)果--------TheVendar-MH先生、下單一輛yellow的Tesla 留言內(nèi)容 : 無留言 TheVendar-MH先生、下單一輛yellow的Tesla 留言內(nèi)容 : 請(qǐng)馬上電話聯(lián)系我復(fù)制代碼好了,就算是關(guān)于這個(gè)訂單的更加復(fù)雜的需求,或者修改需求,不管我們多少各功能在用,我們只要微微一笑,修改下prototype等實(shí)現(xiàn)就好了0.0
如果您覺得還算不錯(cuò)可以關(guān)注我持續(xù)看我的文章,大概方向:前后端語言設(shè)計(jì)模式、如何設(shè)計(jì)好一款框架、源碼導(dǎo)讀、技術(shù)實(shí)踐。
- 青年才俊可以入群交流:147255248
總結(jié)
以上是生活随笔為你收集整理的JavaScript 设计模式 : 巧用'工厂模式'和'创建者'模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 九妹带你了解oracle
- 下一篇: Spring 的3种依赖注入方式