自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web開發(fā)應(yīng)了解的5種設(shè)計(jì)模式

開發(fā) 前端
設(shè)計(jì)模式更多的是指導(dǎo)思想和方法論,而不是現(xiàn)成的代碼,當(dāng)然每種設(shè)計(jì)模式都有每種語(yǔ)言中的具體實(shí)現(xiàn)方式。

 [[384984]]

本文轉(zhuǎn)載自微信公眾號(hào)「前端進(jìn)階之路」,作者三余。轉(zhuǎn)載本文請(qǐng)聯(lián)系前端進(jìn)階之路公眾號(hào)。  

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

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

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

定義

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

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

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

實(shí)現(xiàn)

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

  • 懶漢式
  1. let ShopCar = (function () { 
  2.   let instance; 
  3.   function init() { 
  4.     /*這里定義單例代碼*/ 
  5.     return { 
  6.       buy(good) { 
  7.         this.goods.push(good); 
  8.       }, 
  9.       goods: [], 
  10.     }; 
  11.   } 
  12.   return { 
  13.     getInstance: function () { 
  14.       if (!instance) { 
  15.         instance = init(); 
  16.       } 
  17.       return instance; 
  18.     }, 
  19.   }; 
  20. })(); 
  21. let car1 = ShopCar.getInstance(); 
  22. let car2 = ShopCar.getInstance(); 
  23. car1.buy('橘子'); 
  24. car2.buy('蘋果'); 
  25. console.log(car1.goods); //[ '橘子''蘋果' ] 
  26. console.log(car1 === car2); // true 
  • 餓漢式
  1. var ShopCar = (function () { 
  2.   var instance = init(); 
  3.   function init() { 
  4.     /*這里定義單例代碼*/ return { 
  5.       buy(good) { 
  6.         this.goods.push(good); 
  7.       }, 
  8.       goods: [], 
  9.     }; 
  10.   } 
  11.   return { 
  12.     getInstance: function () { 
  13.       return instance; 
  14.     }, 
  15.   }; 
  16. })(); 
  17. let car1 = ShopCar.getInstance(); 
  18. let car2 = ShopCar.getInstance(); 
  19. car1.buy('橘子'); 
  20. car2.buy('蘋果'); //[ '橘子''蘋果' ] 
  21. console.log(car1.goods); 
  22. console.log(car1 === car2); // true 

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

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

策略模式

定義

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

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

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

實(shí)現(xiàn)

實(shí)例:

  1. // 定義幾個(gè)策略類 
  2. var PaymentMethodStrategy = { 
  3.   BankAccount: function (money) { 
  4.     return money > 50 ? money * 0.7 : money; 
  5.   }, 
  6.   CreditCard: function (money) { 
  7.     return money * 0.8; 
  8.   }, 
  9.   Alipay: function (money) { 
  10.     return money; 
  11.   }, 
  12. }; 
  13. /*環(huán)境類*/ 
  14. var userPay = function (selectedStrategy, money) { 
  15.   return PaymentMethodStrategy[selectedStrategy](money); 
  16. }; 
  17. console.log('銀行卡支付價(jià)格為:' + userPay('BankAccount', 100)); //70 
  18. console.log('支付寶支付價(jià)格為:' + userPay('Alipay', 100)); //100 
  19. 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),或者說執(zhí)行對(duì)應(yīng)對(duì)象的方法,比如你是一個(gè)老師,需要通知班里家長(zhǎng)的時(shí)候,你可以建一個(gè)群(列表)。每次通知事件的時(shí)候只要循環(huán)執(zhí)行這個(gè)列表就好了(群發(fā)),而不用關(guān)心這個(gè)列表里有誰。

實(shí)現(xiàn)

實(shí)例:

  1. // 創(chuàng)建一個(gè)群,保存通知,通知變化之后通知每個(gè)家長(zhǎng)(觸發(fā)所有觀察者對(duì)象) 
  2. class Group { 
  3.   constructor() { 
  4.     this.message = '暫無通知'
  5.     this.parents = []; 
  6.   } 
  7.   getMessage() { 
  8.     return this.message; 
  9.   } 
  10.   setMassage(message) { 
  11.     this.message = message; 
  12.     this.notifyAllObservers(); 
  13.   } 
  14.   notifyAllObservers() { 
  15.     this.parents.forEach((parent) => { 
  16.       parent.update(); 
  17.     }); 
  18.   } 
  19.   attach(parent) { 
  20.     this.parents.push(parent); 
  21.   } 
  22.  
  23. // 觀察者,每個(gè)家長(zhǎng) 
  24. class Parent { 
  25.   constructor(namegroup) { 
  26.     this.name = name
  27.     this.group = group
  28.     this.group.attach(this); 
  29.   } 
  30.   update() { 
  31.     console.log(`${this.name} 收到通知: ${this.group.getMessage()}`); 
  32.   } 
  33.  
  34. let group = new Group(); 
  35. let t1 = new Parent('李媽媽'group); 
  36. let t2 = new Parent('王爸爸'group); 
  37. let t3 = new Parent('張爺爺'group); 
  38.  
  39. group.setMassage('開家長(zhǎng)會(huì)'); 
  40. group.setMassage('開運(yùn)動(dòng)會(huì)'); 
  41. /* 
  42. 李媽媽 收到通知: 開家長(zhǎng)會(huì) 
  43. 王爸爸 收到通知: 開家長(zhǎng)會(huì) 
  44. 張爺爺 收到通知: 開家長(zhǎng)會(huì) 
  45. 李媽媽 收到通知: 開運(yùn)動(dòng)會(huì) 
  46. 王爸爸 收到通知: 開運(yùn)動(dòng)會(huì) 
  47. 張爺爺 收到通知: 開運(yùn)動(dòng)會(huì) 
  48. */ 

發(fā)布訂閱模式

定義

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

實(shí)現(xiàn)

  1. const pubSub = { 
  2.   list:{}, 
  3.   subscribe(key,fn){  // 訂閱 
  4.     if (!this.list[key]) { 
  5.       this.list[key] = []; 
  6.     } 
  7.     this.list[key].push(fn); 
  8.   }, 
  9.   publish(){  // 發(fā)布 
  10.     const arg = arguments; 
  11.     const key = Array.prototype.shift.call(arg); 
  12.     const fns = this.list[key]; 
  13.  
  14.     if(!fns || fns.length<=0) return false
  15.  
  16.     for(var i=0,len=fns.length;i<len;i++){ 
  17.       fns[i].apply(this, arg); 
  18.     } 
  19.   }, 
  20.   unSubscribe(key) {  // 取消訂閱 
  21.     delete this.list[key]; 
  22.   } 
  23. }; 
  24.  
  25. // 進(jìn)行訂閱 
  26. pubSub.subscribe('name', (name) => { 
  27.   console.log('your name is ' + name); 
  28. }); 
  29. pubSub.subscribe('sex', (sex) => { 
  30.   console.log('your sex is ' + sex); 
  31. }); 
  32. // 進(jìn)行發(fā)布 
  33. pubSub.publish('name''ttsy1');  // your name is ttsy1 
  34. pubSub.publish('sex''male');  // your sex is male 

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

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

  1. pubSub.subscribe('name', (name) => { 
  2.   console.log('your name is ' + name); 
  3. }); 
  4. pubSub.subscribe('sex', (sex) => { 
  5.   console.log('your sex is ' + sex); 
  6. }); 
  7. pubSub.unSubscribe('name'); 
  8. pubSub.publish('name''ttsy1');  // 這個(gè)主題被取消訂閱了 
  9. 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è)瓉淼慕Y(jié)構(gòu)和功能基礎(chǔ)上,動(dòng)態(tài)裝飾一些針對(duì)特別場(chǎng)景所適用的方法或?qū)傩裕刺砑右恍┬鹿δ芤栽鰪?qiáng)它的某種能力

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

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

實(shí)現(xiàn)

實(shí)例:

  1. const Man = function () { 
  2.   this.run = function () { 
  3.     console.log('跑步'); 
  4.   }; 
  5. }; 
  6. const Decorator = function (old) { 
  7.   this.oldAbility = old.run; 
  8.   this.fly = function () { 
  9.     console.log('具備飛行能力'); 
  10.   }; 
  11.   this.newAbility = function () { 
  12.     this.oldAbility(); 
  13.     this.fly(); 
  14.   }; 
  15. }; 
  16. const man = new Man(); 
  17. const superMan = new Decorator(man); 
  18. superMan.fly(); // 具備飛行能力 

代理模式

定義

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

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

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

實(shí)現(xiàn)

實(shí)例:

  1. class Letter { 
  2.   constructor(name) { 
  3.     this.name = name
  4.   } 
  5. // 暗戀人小明 
  6. let XiaoMing = { 
  7.   name'小明'
  8.   sendLetter(target) { 
  9.     target.receiveLetter(this.name); 
  10.   }, 
  11. }; 
  12. // 代理小華 
  13. let xiaoHua = { 
  14.   receiveLetter(customer) { 
  15.     // 當(dāng)然要等小紅好心情時(shí)才送情書,也在送情書也才創(chuàng)建情書 
  16.     XiaoHong.listenGoodMood(() => { 
  17.       XiaoHong.receiveLetter(new Letter(customer + '的情書')); 
  18.     }); 
  19.   }, 
  20. }; 
  21. // 心儀對(duì)象小紅 
  22. let XiaoHong = { 
  23.   name'小紅'
  24.   receiveLetter(letter) { 
  25.     console.log(this.name + '收到:' + letter.name); 
  26.   }, 
  27.   listenGoodMood(fn) { 
  28.     setTimeout(() => { 
  29.       fn(); 
  30.     }, 1000); 
  31.   }, 
  32. }; 
  33. XiaoMing.sendLetter(xiaoHua); //小紅收到:小明的情書 

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

  1. var proxy = new Proxy(target, handler); 

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

  1. const scoreList = { wang: 90, li: 60, wu: 100 }; 
  2. const yyProxy = new Proxy(scoreList, { 
  3.   get: function (scoreList, name) { 
  4.     if (scoreList[name] > 69) { 
  5.       console.log('輸出成績(jī)'); 
  6.       return scoreList[name]; 
  7.     } else { 
  8.       console.log('不及格的成績(jī)無法公示'); 
  9.     } 
  10.   }, 
  11.   setfunction (scoreList, name, val) { 
  12.     if (val - scoreList[name] > 10) { 
  13.       console.log('修改成績(jī)'); 
  14.       scoreList[name] = val; 
  15.     } else { 
  16.       console.log('無法修改成績(jī)'); 
  17.     } 
  18.   }, 
  19. }); 
  20. yyProxy['wang'] = 98; //無法修改成績(jī) 
  21. yyProxy['li'] = 80; //修改成績(jī) 

總結(jié)

我曾經(jīng)以為設(shè)計(jì)模式是瘋狂的,遙遠(yuǎn)的軟件開發(fā)指南。然后我發(fā)現(xiàn)我一直在使用它們!我介紹的一些模式已在許多應(yīng)用程序中使用。但歸根結(jié)底,它們只是理論而已。作為開發(fā)人員,是否使用取決于使用后是否使代碼邏輯更易于實(shí)現(xiàn)和維護(hù)。

 

責(zé)任編輯:武曉燕 來源: 前端進(jìn)階之路
相關(guān)推薦

2020-11-08 16:04:03

開發(fā)工具技術(shù)

2018-07-09 11:00:56

軟件架構(gòu)設(shè)計(jì)模式

2012-05-10 09:42:21

web響應(yīng)設(shè)計(jì)

2020-04-23 11:03:09

前端語(yǔ)言開發(fā)

2011-01-10 10:16:12

最新Web開發(fā)技術(shù)

2009-01-04 13:49:17

Java設(shè)計(jì)模式設(shè)計(jì)模式工廠模式

2020-11-18 08:15:39

TypeScript設(shè)計(jì)模式

2012-02-07 14:58:03

Node.js

2017-11-10 13:29:32

監(jiān)控工具RiverbedIT

2013-12-31 10:29:51

2010-09-06 09:26:07

PPP協(xié)議

2013-03-28 13:08:15

Web緩存

2021-02-19 14:07:03

JavaScript編程開發(fā)

2021-04-13 11:32:34

開源開源治理開源代碼項(xiàng)目

2019-08-08 09:00:00

Web開發(fā)Chrome瀏覽器

2012-04-26 10:26:51

移動(dòng)應(yīng)用設(shè)計(jì)

2024-12-31 10:36:40

AIAgent場(chǎng)景

2023-03-03 13:30:18

設(shè)計(jì)模式編程語(yǔ)言

2024-10-14 08:39:29

工廠模式策略模式代碼

2020-11-10 16:01:25

程序員設(shè)計(jì)模式技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)