溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Web開(kāi)發(fā)應(yīng)的設(shè)計(jì)模式有哪些幾種

發(fā)布時(shí)間:2021-10-18 11:29:49 來(lái)源:億速云 閱讀:128 作者:iii 欄目:web開(kāi)發(fā)

這篇文章主要講解了“Web開(kāi)發(fā)應(yīng)的設(shè)計(jì)模式有哪些幾種”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Web開(kāi)發(fā)應(yīng)的設(shè)計(jì)模式有哪些幾種”吧!

什么是設(shè)計(jì)模式?

設(shè)計(jì)模式是對(duì)軟件設(shè)計(jì)開(kāi)發(fā)過(guò)程中反復(fù)出現(xiàn)的某類問(wèn)題的通用解決方案。設(shè)計(jì)模式更多的是指導(dǎo)思想和方法論,而不是現(xiàn)成的代碼,當(dāng)然每種設(shè)計(jì)模式都有每種語(yǔ)言中的具體實(shí)現(xiàn)方式。學(xué)習(xí)設(shè)計(jì)模式更多的是理解各種模式的內(nèi)在思想和解決的問(wèn)題,畢竟這是前人無(wú)數(shù)經(jīng)驗(yàn)總結(jié)成的最佳實(shí)踐,而代碼實(shí)現(xiàn)則是對(duì)加深理解的輔助。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。在本文中,我將介紹其中常見(jiàn)的五種設(shè)計(jì)模式在JavaScript中實(shí)際使用場(chǎng)景:

單例設(shè)計(jì)模式

定義

單例模式僅允許類或?qū)ο缶哂袉蝹€(gè)實(shí)例,并且它使用全局變量來(lái)存儲(chǔ)該實(shí)例。

實(shí)現(xiàn)方法是判斷是否存在該對(duì)象的實(shí)例,如果已存在則不再創(chuàng)建

使用場(chǎng)景適用于業(yè)務(wù)場(chǎng)景中只能存在一個(gè)的實(shí)例,比如彈窗,購(gòu)物車

實(shí)現(xiàn)

單例模式分為懶漢式和餓漢式:

  • 懶漢式

let ShopCar = (function () {   let instance;   function init() {     /*這里定義單例代碼*/     return {       buy(good) {         this.goods.push(good);       },       goods: [],     };   }   return {     getInstance: function () {       if (!instance) {         instance = init();       }       return instance;     },   }; })(); let car1 = ShopCar.getInstance(); let car2 = ShopCar.getInstance(); car1.buy('橘子'); car2.buy('蘋(píng)果'); console.log(car1.goods); //[ '橘子', '蘋(píng)果' ] console.log(car1 === car2); // true
  • 餓漢式

var ShopCar = (function () {   var instance = init();   function init() {     /*這里定義單例代碼*/ return {       buy(good) {         this.goods.push(good);       },       goods: [],     };   }   return {     getInstance: function () {       return instance;     },   }; })(); let car1 = ShopCar.getInstance(); let car2 = ShopCar.getInstance(); car1.buy('橘子'); car2.buy('蘋(píng)果'); //[ '橘子', '蘋(píng)果' ] console.log(car1.goods); console.log(car1 === car2); // true

懶漢式在類加載時(shí),不創(chuàng)建實(shí)例,因此類加載速度快,但運(yùn)行時(shí)獲取對(duì)象的速度慢;

餓漢式在類加載時(shí)就完成了初始化,所以類加載較慢,但獲取對(duì)象的速度快

策略模式

定義

策略模式定義一系列的算法,將每一個(gè)算法封裝起來(lái),并讓他們可以相互替換。

實(shí)現(xiàn)方法定義一組可變的策略類封裝具體算法,定義一組不變的環(huán)境類將請(qǐng)求委托給某一個(gè)策略類

使用場(chǎng)景適用于業(yè)務(wù)場(chǎng)景中需要判斷多種條件,甚至包含復(fù)雜條件嵌套的,可以使用策略模式來(lái)提升代碼的可維護(hù)性和可讀性。比如支付,博客權(quán)限校驗(yàn)

實(shí)現(xiàn)

實(shí)例:

// 定義幾個(gè)策略類 var PaymentMethodStrategy = {   BankAccount: function (money) {     return money > 50 ? money * 0.7 : money;   },   CreditCard: function (money) {     return money * 0.8;   },   Alipay: function (money) {     return money;   }, }; /*環(huán)境類*/ var userPay = function (selectedStrategy, money) {   return PaymentMethodStrategy[selectedStrategy](money); }; console.log('銀行卡支付價(jià)格為:' + userPay('BankAccount', 100)); //70 console.log('支付寶支付價(jià)格為:' + userPay('Alipay', 100)); //100 console.log('信用卡支付價(jià)格為:' + userPay('CreditCard', 100)); //80

觀察者模式

定義

觀察者模式是對(duì)象的行為模式,在對(duì)象之間定義了一對(duì)多的依賴關(guān)系,就是多個(gè)觀察者和一個(gè)被觀察者之間的關(guān)系,當(dāng)被觀察者發(fā)生變化的時(shí)候,會(huì)通知所有的觀察者對(duì)象,他們做出相對(duì)應(yīng)的操作。

實(shí)現(xiàn)方法定義一組可變的策略類封裝具體算法,定義一組不變的環(huán)境類將請(qǐng)求委托給某一個(gè)策略類

使用場(chǎng)景適用于業(yè)務(wù)場(chǎng)景中當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),需要自動(dòng)通知其他關(guān)聯(lián)對(duì)象,自動(dòng)刷新對(duì)象狀態(tài),或者說(shuō)執(zhí)行對(duì)應(yīng)對(duì)象的方法,比如你是一個(gè)老師,需要通知班里家長(zhǎng)的時(shí)候,你可以建一個(gè)群(列表)。每次通知事件的時(shí)候只要循環(huán)執(zhí)行這個(gè)列表就好了(群發(fā)),而不用關(guān)心這個(gè)列表里有誰(shuí)。

實(shí)現(xiàn)

實(shí)例:

// 創(chuàng)建一個(gè)群,保存通知,通知變化之后通知每個(gè)家長(zhǎng)(觸發(fā)所有觀察者對(duì)象) class Group {   constructor() {     this.message = '暫無(wú)通知';     this.parents = [];   }   getMessage() {     return this.message;   }   setMassage(message) {     this.message = message;     this.notifyAllObservers();   }   notifyAllObservers() {     this.parents.forEach((parent) => {       parent.update();     });   }   attach(parent) {     this.parents.push(parent);   } }  // 觀察者,每個(gè)家長(zhǎng) class Parent {   constructor(name, group) {     this.name = name;     this.group = group;     this.group.attach(this);   }   update() {     console.log(`${this.name} 收到通知: ${this.group.getMessage()}`);   } }  let group = new Group(); let t1 = new Parent('李媽媽', group); let t2 = new Parent('王爸爸', group); let t3 = new Parent('張爺爺', group);  group.setMassage('開(kāi)家長(zhǎng)會(huì)'); group.setMassage('開(kāi)運(yùn)動(dòng)會(huì)'); /* 李媽媽 收到通知: 開(kāi)家長(zhǎng)會(huì) 王爸爸 收到通知: 開(kāi)家長(zhǎng)會(huì) 張爺爺 收到通知: 開(kāi)家長(zhǎng)會(huì) 李媽媽 收到通知: 開(kāi)運(yùn)動(dòng)會(huì) 王爸爸 收到通知: 開(kāi)運(yùn)動(dòng)會(huì) 張爺爺 收到通知: 開(kāi)運(yùn)動(dòng)會(huì) */

發(fā)布訂閱模式

定義

發(fā)布訂閱模式指的是希望接收通知的對(duì)象(Subscriber)基于一個(gè)主題通過(guò)自定義事件訂閱主題,發(fā)布事件的對(duì)象(Publisher)通過(guò)發(fā)布主題事件的方式通知各個(gè)訂閱該主題的  Subscriber 對(duì)象。

實(shí)現(xiàn)

const pubSub = {   list:{},   subscribe(key,fn){  // 訂閱     if (!this.list[key]) {       this.list[key] = [];     }     this.list[key].push(fn);   },   publish(){  // 發(fā)布     const arg = arguments;     const key = Array.prototype.shift.call(arg);     const fns = this.list[key];      if(!fns || fns.length<=0) return false;      for(var i=0,len=fns.length;i<len;i++){       fns[i].apply(this, arg);     }   },   unSubscribe(key) {  // 取消訂閱     delete this.list[key];   } };  // 進(jìn)行訂閱 pubSub.subscribe('name', (name) => {   console.log('your name is ' + name); }); pubSub.subscribe('sex', (sex) => {   console.log('your sex is ' + sex); }); // 進(jìn)行發(fā)布 pubSub.publish('name', 'ttsy1');  // your name is ttsy1 pubSub.publish('sex', 'male');  // your sex is male

上述代碼的訂閱是基于 name 和 sex 主題來(lái)自定義事件,發(fā)布是通過(guò) name 和 sex  主題并傳入自定義事件的參數(shù),最終觸發(fā)了特定主題的自定義事件。

可以通過(guò) unSubscribe 方法取消特定主題的訂閱。

pubSub.subscribe('name', (name) => {   console.log('your name is ' + name); }); pubSub.subscribe('sex', (sex) => {   console.log('your sex is ' + sex); }); pubSub.unSubscribe('name'); pubSub.publish('name', 'ttsy1');  // 這個(gè)主題被取消訂閱了 pubSub.publish('sex', 'male');  // your sex is male

觀察者模式 VS 發(fā)布訂閱模式:

觀察者模式與發(fā)布訂閱模式都是定義了一個(gè)一對(duì)多的依賴關(guān)系,當(dāng)有關(guān)狀態(tài)發(fā)生變更時(shí)則執(zhí)行相應(yīng)的更新。

不同的是,在觀察者模式中依賴于 Subject 對(duì)象的一系列 Observer  對(duì)象在被通知之后只能執(zhí)行同一個(gè)特定的更新方法,而在發(fā)布訂閱模式中則可以基于不同的主題去執(zhí)行不同的自定義事件。

相對(duì)而言,發(fā)布訂閱模式比觀察者模式要更加靈活多變。

裝飾器模式

定義

在不改變?cè)瓉?lái)的結(jié)構(gòu)和功能基礎(chǔ)上,動(dòng)態(tài)裝飾一些針對(duì)特別場(chǎng)景所適用的方法或?qū)傩?,即添加一些新功能以增?qiáng)它的某種能力

實(shí)現(xiàn)方法定義一組可變的策略類封裝具體算法,定義一組不變的環(huán)境類將請(qǐng)求委托給某一個(gè)策略類

使用場(chǎng)景原有方法維持不變,在原有方法上再掛載其他方法來(lái)滿足現(xiàn)有需求;函數(shù)的解耦,將函數(shù)拆分成多個(gè)可復(fù)用的函數(shù),再將拆分出來(lái)的函數(shù)掛載到某個(gè)函數(shù)上,實(shí)現(xiàn)相同的效果但增強(qiáng)了復(fù)用性。比如多孔插座,機(jī)車改裝

實(shí)現(xiàn)

實(shí)例:

const Man = function () {   this.run = function () {     console.log('跑步');   }; }; const Decorator = function (old) {   this.oldAbility = old.run;   this.fly = function () {     console.log('具備飛行能力');   };   this.newAbility = function () {     this.oldAbility();     this.fly();   }; }; const man = new Man(); const superMan = new Decorator(man); superMan.fly(); // 具備飛行能力

代理模式

定義

代理模式給某一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)原對(duì)象的引用。通俗的來(lái)講代理模式就是我們生活中常見(jiàn)的中介。

實(shí)現(xiàn)方法定義一個(gè)委托者和一個(gè)代理,需要委托的事情在代理中完成

使用場(chǎng)景在某些情況下,一個(gè)客戶類不想或者不能直接引用一個(gè)委托對(duì)象,而代理類對(duì)象可以在客戶類和委托對(duì)象之間起到中介的作用。代理可以幫客戶過(guò)濾掉一些請(qǐng)求并且把一些開(kāi)銷大的對(duì)象,延遲到真正需要它時(shí)才創(chuàng)建。中介購(gòu)車、代購(gòu)、課代表替老師收作業(yè)

實(shí)現(xiàn)

實(shí)例:

class Letter {   constructor(name) {     this.name = name;   } } // 暗戀人小明 let XiaoMing = {   name: '小明',   sendLetter(target) {     target.receiveLetter(this.name);   }, }; // 代理小華 let xiaoHua = {   receiveLetter(customer) {     // 當(dāng)然要等小紅好心情時(shí)才送情書(shū),也在送情書(shū)也才創(chuàng)建情書(shū)     XiaoHong.listenGoodMood(() => {       XiaoHong.receiveLetter(new Letter(customer + '的情書(shū)'));     });   }, }; // 心儀對(duì)象小紅 let XiaoHong = {   name: '小紅',   receiveLetter(letter) {     console.log(this.name + '收到:' + letter.name);   },   listenGoodMood(fn) {     setTimeout(() => {       fn();     }, 1000);   }, }; XiaoMing.sendLetter(xiaoHua); //小紅收到:小明的情書(shū)

Proxy 是 ES6 提供的專門以代理角色出現(xiàn)的代理器,Vue 3.0 的響應(yīng)式數(shù)據(jù)部分棄用了 Object.defineProperty,使用  Proxy 來(lái)代替它。

var proxy = new Proxy(target, handler);

現(xiàn)在用Proxy模擬一下另一種場(chǎng)景:為了保護(hù)不及格的同學(xué),課代表拿到全班成績(jī)單后只會(huì)公示及格人的成績(jī)。對(duì)考分有疑問(wèn)的考生,復(fù)議后新分?jǐn)?shù)比以前大10分才有權(quán)利去更新成績(jī)

const scoreList = { wang: 90, li: 60, wu: 100 }; const yyProxy = new Proxy(scoreList, {   get: function (scoreList, name) {     if (scoreList[name] > 69) {       console.log('輸出成績(jī)');       return scoreList[name];     } else {       console.log('不及格的成績(jī)無(wú)法公示');     }   },   set: function (scoreList, name, val) {     if (val - scoreList[name] > 10) {       console.log('修改成績(jī)');       scoreList[name] = val;     } else {       console.log('無(wú)法修改成績(jī)');     }   }, }); yyProxy['wang'] = 98; //無(wú)法修改成績(jī) yyProxy['li'] = 80; //修改成績(jī)

感謝各位的閱讀,以上就是“Web開(kāi)發(fā)應(yīng)的設(shè)計(jì)模式有哪些幾種”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Web開(kāi)發(fā)應(yīng)的設(shè)計(jì)模式有哪些幾種這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI