JavaScript設(shè)計(jì)模式
(給前端大學(xué)加星標(biāo),提升前端技能.)
設(shè)計(jì)模式的定義:在面向?qū)ο筌浖O(shè)計(jì)過程中針對(duì)特定問題的簡(jiǎn)潔而優(yōu)雅的解決方案作者:考拉海購前端團(tuán)隊(duì)
https://juejin.im/post/59df4f74f265da430f311909
當(dāng)然我們可以用一個(gè)通俗的說法:設(shè)計(jì)模式是解決某個(gè)特定場(chǎng)景下對(duì)某種問題的解決方案。因此,當(dāng)我們遇到合適的場(chǎng)景時(shí),我們可能會(huì)條件反射一樣自然而然想到符合這種場(chǎng)景的設(shè)計(jì)模式。比如,當(dāng)系統(tǒng)中某個(gè)接口的結(jié)構(gòu)已經(jīng)無法滿足我們現(xiàn)在的業(yè)務(wù)需求,但又不能改動(dòng)這個(gè)接口,因?yàn)榭赡茉瓉淼南到y(tǒng)很多功能都依賴于這個(gè)接口,改動(dòng)接口會(huì)牽扯到太多文件。因此應(yīng)對(duì)這種場(chǎng)景,我們可以很快地想到可以用適配器模式來解決這個(gè)問題。下面介紹幾種在JavaScript中常見的幾種設(shè)計(jì)模式:
1、單例模式
單例模式的定義:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。實(shí)現(xiàn)的方法為先判斷實(shí)例存在與否,如果存在則直接返回,如果不存在就創(chuàng)建了再返回,這就確保了一個(gè)類只有一個(gè)實(shí)例對(duì)象。適用場(chǎng)景:一個(gè)單一對(duì)象。比如:彈窗,無論點(diǎn)擊多少次,彈窗只應(yīng)該被創(chuàng)建一次。class CreateUser {constructor(name) {this.name = name;this.getName();}getName() {return this.name;}}// 代理實(shí)現(xiàn)單例模式var ProxyMode = (function() {var instance = null;return function(name) {if(!instance) {instance = new CreateUser(name);}return instance;}})();// 測(cè)試單體模式的實(shí)例var a = new ProxyMode("aaa");var b = new ProxyMode("bbb");// 因?yàn)閱误w模式是只實(shí)例化一次,所以下面的實(shí)例是相等的console.log(a === b); //true
2、策略模式
策略模式的定義:定義一系列的算法,把他們一個(gè)個(gè)封裝起來,并且使他們可以相互替換。策略模式的目的就是將算法的使用算法的實(shí)現(xiàn)分離開來。一個(gè)基于策略模式的程序至少由兩部分組成。第一個(gè)部分是一組策略類(可變),策略類封裝了具體的算法,并負(fù)責(zé)具體的計(jì)算過程。第二個(gè)部分是環(huán)境類Context(不變),Context接受客戶的請(qǐng)求,隨后將請(qǐng)求委托給某一個(gè)策略類。要做到這一點(diǎn),說明Context中要維持對(duì)某個(gè)策略對(duì)象的引用。/*策略類*/var levelOBJ = {"A": function(money) {return money * 4;},"B" : function(money) {return money * 3;},"C" : function(money) {return money * 2;}};/*環(huán)境類*/var calculateBouns =function(level,money) {return levelOBJ[level](money);};console.log(calculateBouns('A',10000)); // 40000
3、代理模式
代理模式的定義:為一個(gè)對(duì)象提供一個(gè)代用品或占位符,以便控制對(duì)它的訪問。常用的虛擬代理形式:某一個(gè)花銷很大的操作,可以通過虛擬代理的方式延遲到這種需要它的時(shí)候才去創(chuàng)建(例:使用虛擬代理實(shí)現(xiàn)圖片懶加載)圖片懶加載的方式:先通過一張loading圖占位,然后通過異步的方式加載圖片,等圖片加載好了再把完成的圖片加載到img標(biāo)簽里面。使用代理模式實(shí)現(xiàn)圖片懶加載的優(yōu)點(diǎn)還有符合單一職責(zé)原則。減少一個(gè)類或方法的粒度和耦合度。var imgFunc = (function() {var imgNode = document.createElement('img');document.body.appendChild(imgNode);return {setSrc: function(src) {imgNode.src = src;}}})();var proxyImage = (function() {var img = new Image();img.onload = function() {imgFunc.setSrc(this.src);}return {setSrc: function(src) {imgFunc.setSrc('./loading,gif');img.src = src;}}})();proxyImage.setSrc('./pic.png');
4、中介者模式
中介者模式的定義:通過一個(gè)中介者對(duì)象,其他所有的相關(guān)對(duì)象都通過該中介者對(duì)象來通信,而不是相互引用,當(dāng)其中的一個(gè)對(duì)象發(fā)生改變時(shí),只需要通知中介者對(duì)象即可。通過中介者模式可以解除對(duì)象與對(duì)象之間的緊耦合關(guān)系。例如:現(xiàn)實(shí)生活中,航線上的飛機(jī)只需要和機(jī)場(chǎng)的塔臺(tái)通信就能確定航線和飛行狀態(tài),而不需要和所有飛機(jī)通信。同時(shí)塔臺(tái)作為中介者,知道每架飛機(jī)的飛行狀態(tài),所以可以安排所有飛機(jī)的起降和航線安排。中介者模式適用的場(chǎng)景:例如購物車需求,存在商品選擇表單、顏色選擇表單、購買數(shù)量表單等等,都會(huì)觸發(fā)change事件,那么可以通過中介者來轉(zhuǎn)發(fā)處理這些事件,實(shí)現(xiàn)各個(gè)事件間的解耦,僅僅維護(hù)中介者對(duì)象即可。var goods = { //手機(jī)庫存'red|32G': 3,'red|64G': 1,'blue|32G': 7,'blue|32G': 6,};//中介者var mediator = (function() {var colorSelect = document.getElementById('colorSelect');var memorySelect = document.getElementById('memorySelect');var numSelect = document.getElementById('numSelect');return {changed: function(obj) {switch(obj){case colorSelect://TODObreak;case memorySelect://TODObreak;case numSelect://TODObreak;}}}})();colorSelect.onchange = function() {mediator.changed(this);};memorySelect.onchange = function() {mediator.changed(this);};numSelect.onchange = function() {mediator.changed(this);};
5、裝飾者模式
裝飾者模式的定義:在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地添加方法。例如:現(xiàn)有4種型號(hào)的自行車分別被定義成一個(gè)單獨(dú)的類,如果給每輛自行車都加上前燈、尾燈、鈴鐺這3個(gè)配件,如果用類繼承的方式,需要?jiǎng)?chuàng)建4*3=12個(gè)子類。但如果通過裝飾者模式,只需要?jiǎng)?chuàng)建3個(gè)類。裝飾者模式適用的場(chǎng)景:原有方法維持不變,在原有方法上再掛載其他方法來滿足現(xiàn)有需求;函數(shù)的解耦,將函數(shù)拆分成多個(gè)可復(fù)用的函數(shù),再將拆分出來的函數(shù)掛載到某個(gè)函數(shù)上,實(shí)現(xiàn)相同的效果但增強(qiáng)了復(fù)用性。例:用AOP裝飾函數(shù)實(shí)現(xiàn)裝飾者模式本文完~Function.prototype.before = function(beforefn) {var self = this; //保存原函數(shù)引用return function(){ //返回包含了原函數(shù)和新函數(shù)的 '代理函數(shù)'beforefn.apply(this, arguments); //執(zhí)行新函數(shù),修正thisreturn self.apply(this,arguments); //執(zhí)行原函數(shù)}}Function.prototype.after = function(afterfn) {var self = this;return function(){var ret = self.apply(this,arguments);afterfn.apply(this, arguments);return ret;}}var func = function() {console.log('2');}//func1和func3為掛載函數(shù)var func1 = function() {console.log('1');}var func3 = function() {console.log('3');}func = func.before(func1).after(func3);func();
分享前端好文,點(diǎn)亮?在看?
評(píng)論
圖片
表情
