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

前端需要了解的9種設(shè)計(jì)模式

開發(fā) 前端
設(shè)計(jì)模式是對(duì)軟件設(shè)計(jì)開發(fā)過程中反復(fù)出現(xiàn)的某類問題的通用解決方案。設(shè)計(jì)模式更多的是指導(dǎo)思想和方法論,而不是現(xiàn)成的代碼,當(dāng)然每種設(shè)計(jì)模式都有每種語言中的具體實(shí)現(xiàn)方式。

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

設(shè)計(jì)模式是對(duì)軟件設(shè)計(jì)開發(fā)過程中反復(fù)出現(xiàn)的某類問題的通用解決方案。設(shè)計(jì)模式更多的是指導(dǎo)思想和方法論,而不是現(xiàn)成的代碼,當(dāng)然每種設(shè)計(jì)模式都有每種語言中的具體實(shí)現(xiàn)方式。學(xué)習(xí)設(shè)計(jì)模式更多的是理解各種模式的內(nèi)在思想和解決的問題,畢竟這是前人無數(shù)經(jīng)驗(yàn)總結(jié)成的優(yōu)秀實(shí)踐,而代碼實(shí)現(xiàn)則是對(duì)加深理解的輔助。

[[323404]]

設(shè)計(jì)模式的類型

設(shè)計(jì)模式可以分為三大類:

  1. 結(jié)構(gòu)型模式(Structural Patterns): 通過識(shí)別系統(tǒng)中組件間的簡單關(guān)系來簡化系統(tǒng)的設(shè)計(jì)。
  2. 創(chuàng)建型模式(Creational Patterns): 處理對(duì)象的創(chuàng)建,根據(jù)實(shí)際情況使用合適的方式創(chuàng)建對(duì)象。常規(guī)的對(duì)象創(chuàng)建方式可能會(huì)導(dǎo)致設(shè)計(jì)上的問題,或增加設(shè)計(jì)的復(fù)雜度。創(chuàng)建型模式通過以某種方式控制對(duì)象的創(chuàng)建來解決問題。
  3. 行為型模式(Behavioral Patterns): 用于識(shí)別對(duì)象之間常見的交互模式并加以實(shí)現(xiàn),如此,增加了這些交互的靈活性。

以上定義非常的抽象和晦澀,對(duì)于我們初學(xué)者并沒有太多幫助,要了解這些設(shè)計(jì)模式真正的作用和價(jià)值還是需要通過實(shí)踐去加以理解。這三大類設(shè)計(jì)模式又可以分成更多的小類,如下圖:

下面我們選擇一些在前端開發(fā)過程中常見的模式進(jìn)行一一講解。

一. 結(jié)構(gòu)型模式(Structural Patterns)

1. 外觀模式(Facade Pattern)

外觀模式是最常見的設(shè)計(jì)模式之一,它為子系統(tǒng)中的一組接口提供一個(gè)統(tǒng)一的高層接口,使子系統(tǒng)更容易使用。簡而言之外觀設(shè)計(jì)模式就是把多個(gè)子系統(tǒng)中復(fù)雜邏輯進(jìn)行抽象,從而提供一個(gè)更統(tǒng)一、更簡潔、更易用的API。很多我們常用的框架和庫基本都遵循了外觀設(shè)計(jì)模式,比如JQuery就把復(fù)雜的原生DOM操作進(jìn)行了抽象和封裝,并消除了瀏覽器之間的兼容問題,從而提供了一個(gè)更高級(jí)更易用的版本。其實(shí)在平時(shí)工作中我們也會(huì)經(jīng)常用到外觀模式進(jìn)行開發(fā),只是我們不自知而已。

比如,我們可以應(yīng)用外觀模式封裝一個(gè)統(tǒng)一的DOM元素事件綁定/取消方法,用于兼容不同版本的瀏覽器和更方便的調(diào)用:

  1. // 綁定事件 
  2. function addEvent(element, event, handler) { 
  3.   if (element.addEventListener) { 
  4.     element.addEventListener(event, handler, false); 
  5.   } else if (element.attachEvent) { 
  6.     element.attachEvent('on' + event, handler); 
  7.   } else { 
  8.     element['on' + event] = fn; 
  9.   } 
  10.  
  11. // 取消綁定 
  12. function removeEvent(element, event, handler) { 
  13.   if (element.removeEventListener) { 
  14.     element.removeEventListener(event, handler, false); 
  15.   } else if (element.detachEvent) { 
  16.     element.detachEvent('on' + event, handler); 
  17.   } else { 
  18.     element['on' + event] = null
  19.   } 

2. 代理模式(Proxy Pattern)

首先,一切皆可代理,不管是在實(shí)現(xiàn)世界還是計(jì)算機(jī)世界?,F(xiàn)實(shí)世界中買房有中介、打官司有律師、投資有經(jīng)紀(jì)人,他們都是代理,由他們幫你處理由于你缺少時(shí)間或者專業(yè)技能而無法完成的事務(wù)。類比到計(jì)算機(jī)領(lǐng)域,代理也是一樣的作用,當(dāng)訪問一個(gè)對(duì)象本身的代價(jià)太高(比如太占內(nèi)存、初始化時(shí)間太長等)或者需要增加額外的邏輯又不修改對(duì)象本身時(shí)便可以使用代理。ES6中也增加了 Proxy 的功能。

歸納一下,代理模式可以解決以下的問題:

  1. 增加對(duì)一個(gè)對(duì)象的訪問控制
  2. 當(dāng)訪問一個(gè)對(duì)象的過程中需要增加額外的邏輯

要實(shí)現(xiàn)代理模式需要三部分:

  1. Real Subject:真實(shí)對(duì)象
  2. Proxy:代理對(duì)象
  3. Subject接口:Real Subject 和 Proxy都需要實(shí)現(xiàn)的接口,這樣Proxy才能被當(dāng)成Real Subject的“替身”使用

比如有一個(gè)股票價(jià)格查詢接口,調(diào)用這個(gè)接口需要比較久的時(shí)間(用 setTimeout 模擬2s的調(diào)用時(shí)間):

StockPriceAPI:

  1. function StockPriceAPI() { 
  2.   // Subject Interface實(shí)現(xiàn) 
  3.   this.getValue = function (stock, callback) { 
  4.     console.log('Calling external API ... '); 
  5.     setTimeout(() => { 
  6.       switch (stock) { 
  7.         case 'GOOGL'
  8.           callback('$1265.23'); 
  9.           break; 
  10.         case 'AAPL'
  11.           callback('$287.05'); 
  12.           break; 
  13.         case 'MSFT'
  14.           callback('$173.70'); 
  15.           break; 
  16.         default
  17.           callback(''); 
  18.       } 
  19.     }, 2000); 
  20.   } 

我們不希望每次都去請(qǐng)求遠(yuǎn)程接口,而是增加緩存機(jī)制,當(dāng)有緩存的時(shí)候就直接從緩存中獲取,否則再去請(qǐng)求遠(yuǎn)程接口。我們可以通過一個(gè)proxy來實(shí)現(xiàn):

StockPriceAPIProxy:

  1. function StockPriceAPIProxy() { 
  2.   // 緩存對(duì)象 
  3.   this.cache = {}; 
  4.   // 真實(shí)API對(duì)象 
  5.   this.realAPI = new StockPriceAPI(); 
  6.   // Subject Interface實(shí)現(xiàn) 
  7.   this.getValue = function (stock, callback) { 
  8.     const cachedPrice = this.cache[stock]; 
  9.     if (cachedPrice) { 
  10.       console.log('Got price from cache'); 
  11.       callback(cachedPrice); 
  12.     } else { 
  13.       this.realAPI.getValue(stock, (price) => { 
  14.         this.cache[stock] = price; 
  15.         callback(price); 
  16.       }); 
  17.     } 
  18.   } 

注意,Proxy需要和真實(shí)對(duì)象一樣實(shí)現(xiàn) getValue() 方法,getValue()就屬于 Subject 接口。

測試一下:

  1. const api = new StockPriceAPIProxy(); 
  2. api.getValue('GOOGL', (price) => { console.log(price) }); 
  3. api.getValue('AAPL', (price) => { console.log(price) }); 
  4. api.getValue('MSFT', (price) => { console.log(price) }); 
  5.  
  6. setTimeout(() => { 
  7.   api.getValue('GOOGL', (price) => { console.log(price) }); 
  8.   api.getValue('AAPL', (price) => { console.log(price) }); 
  9.   api.getValue('MSFT', (price) => { console.log(price) }); 
  10. }, 3000) 

輸出:

  1. Calling external API ...  
  2. Calling external API ...  
  3. Calling external API ...  
  4. $1265.23 
  5. $287.05 
  6. $173.70 
  7. Got price from cache 
  8. $1265.23 
  9. Got price from cache 
  10. $287.05 
  11. Got price from cache 
  12. $173.70 

二. 創(chuàng)建型模式(Creational Patterns)

1. 工廠模式(Factory Pattern)

現(xiàn)實(shí)生活中的工廠按照既定程序制造產(chǎn)品,隨著生產(chǎn)原料和流程不同生產(chǎn)出來的產(chǎn)品也會(huì)有區(qū)別。應(yīng)用到軟件工程的領(lǐng)域,工廠可以看成是一個(gè)制造其他對(duì)象的對(duì)象,制造出的對(duì)象也會(huì)隨著傳入工廠對(duì)象參數(shù)的不同而有所區(qū)別。

什么場景適合應(yīng)用工廠模式而不是直接 new 一個(gè)對(duì)象呢?當(dāng)構(gòu)造函數(shù)過多不方便管理,且需要?jiǎng)?chuàng)建的對(duì)象之間存在某些關(guān)聯(lián)(有同一個(gè)父類、實(shí)現(xiàn)同一個(gè)接口等)時(shí),不妨使用工廠模式。工廠模式提供一種集中化、統(tǒng)一化的方式,避免了分散創(chuàng)建對(duì)象導(dǎo)致的代碼重復(fù)、靈活性差的問題。

以上圖為例,我們構(gòu)造一個(gè)簡單的汽車工廠來生產(chǎn)汽車:

  1. // 汽車構(gòu)造函數(shù) 
  2. function SuzukiCar(color) { 
  3.   this.color = color; 
  4.   this.brand = 'Suzuki'
  5.  
  6. // 汽車構(gòu)造函數(shù) 
  7. function HondaCar(color) { 
  8.   this.color = color; 
  9.   this.brand = 'Honda'
  10.  
  11. // 汽車構(gòu)造函數(shù) 
  12. function BMWCar(color) { 
  13.   this.color = color; 
  14.   this.brand = 'BMW'
  15.  
  16. // 汽車品牌枚舉 
  17. const BRANDS = { 
  18.   suzuki: 1, 
  19.   honda: 2, 
  20.   bmw: 3 
  21.  
  22. /** 
  23.  * 汽車工廠 
  24.  */ 
  25. function CarFactory() { 
  26.   this.create = function (brand, color) { 
  27.     switch (brand) { 
  28.       case BRANDS.suzuki: 
  29.         return new SuzukiCar(color); 
  30.       case BRANDS.honda: 
  31.         return new HondaCar(color); 
  32.       case BRANDS.bmw: 
  33.         return new BMWCar(color); 
  34.       default
  35.         break; 
  36.     } 
  37.   } 

測試一下:

  1. const carFactory = new CarFactory(); 
  2. const cars = []; 
  3.  
  4. cars.push(carFactory.create(BRANDS.suzuki, 'brown')); 
  5. cars.push(carFactory.create(BRANDS.honda, 'grey')); 
  6. cars.push(carFactory.create(BRANDS.bmw, 'red')); 
  7.  
  8. function say() { 
  9.   console.log(`Hi, I am a ${this.color} ${this.brand} car`); 
  10.  
  11. for (const car of cars) { 
  12.   say.call(car); 

輸出:

  1. Hi, I am a brown Suzuki car 
  2. Hi, I am a grey Honda car 
  3. Hi, I am a red BMW car 

使用工廠模式之后,不再需要重復(fù)引入一個(gè)個(gè)構(gòu)造函數(shù),只需要引入工廠對(duì)象就可以方便的創(chuàng)建各類對(duì)象。

2. 單例模式(Singleton Pattern)

顧名思義,單例模式中Class的實(shí)例個(gè)數(shù)最多為1。當(dāng)需要一個(gè)對(duì)象去貫穿整個(gè)系統(tǒng)執(zhí)行某些任務(wù)時(shí),單例模式就派上了用場。而除此之外的場景盡量避免單例模式的使用,因?yàn)閱卫J綍?huì)引入全局狀態(tài),而一個(gè)健康的系統(tǒng)應(yīng)該避免引入過多的全局狀態(tài)。

實(shí)現(xiàn)單例模式需要解決以下幾個(gè)問題:

  1. 如何確定Class只有一個(gè)實(shí)例?
  2. 如何簡便的訪問Class的唯一實(shí)例?
  3. Class如何控制實(shí)例化的過程?
  4. 如何將Class的實(shí)例個(gè)數(shù)限制為1?

我們一般通過實(shí)現(xiàn)以下兩點(diǎn)來解決上述問題:

  1. 隱藏Class的構(gòu)造函數(shù),避免多次實(shí)例化
  2. 通過暴露一個(gè) getInstance() 方法來創(chuàng)建/獲取唯一實(shí)例

Javascript中單例模式可以通過以下方式實(shí)現(xiàn):

  1. // 單例構(gòu)造器 
  2. const FooServiceSingleton = (function () { 
  3.   // 隱藏的Class的構(gòu)造函數(shù) 
  4.   function FooService() {} 
  5.  
  6.   // 未初始化的單例對(duì)象 
  7.   let fooService; 
  8.  
  9.   return { 
  10.     // 創(chuàng)建/獲取單例對(duì)象的函數(shù) 
  11.     getInstance: function () { 
  12.       if (!fooService) { 
  13.         fooService = new FooService(); 
  14.       } 
  15.       return fooService; 
  16.     } 
  17.   } 
  18. })(); 

實(shí)現(xiàn)的關(guān)鍵點(diǎn)有:1. 使用 IIFE創(chuàng)建局部作用域并即時(shí)執(zhí)行;2. getInstance() 為一個(gè) 閉包 ,使用閉包保存局部作用域中的單例對(duì)象并返回。

我們可以驗(yàn)證下單例對(duì)象是否創(chuàng)建成功:

  1. const fooService1 = FooServiceSingleton.getInstance(); 
  2. const fooService2 = FooServiceSingleton.getInstance(); 
  3.  
  4. console.log(fooService1 === fooService2); // true 

三. 行為型模式(Behavioral Patterns)

1. 策略模式(Strategy Pattern)

策略模式簡單描述就是:對(duì)象有某個(gè)行為,但是在不同的場景中,該行為有不同的實(shí)現(xiàn)算法。比如每個(gè)人都要“交個(gè)人所得稅”,但是“在美國交個(gè)人所得稅”和“在中國交個(gè)人所得稅”就有不同的算稅方法。最常見的使用策略模式的場景如登錄鑒權(quán),鑒權(quán)算法取決于用戶的登錄方式是手機(jī)、郵箱或者第三方的微信登錄等等,而且登錄方式也只有在運(yùn)行時(shí)才能獲取,獲取到登錄方式后再動(dòng)態(tài)的配置鑒權(quán)策略。所有這些策略應(yīng)該實(shí)現(xiàn)統(tǒng)一的接口,或者說有統(tǒng)一的行為模式。Node 生態(tài)里著名的鑒權(quán)庫 Passport.js API的設(shè)計(jì)就應(yīng)用了策略模式。

還是以登錄鑒權(quán)的例子我們仿照 passport.js 的思路通過代碼來理解策略模式:

  1. /** 
  2.  * 登錄控制器 
  3.  */ 
  4. function LoginController() { 
  5.   this.strategy = undefined; 
  6.   this.setStrategy = function (strategy) { 
  7.     this.strategy = strategy; 
  8.     this.login = this.strategy.login; 
  9.   } 
  10.  
  11. /** 
  12.  * 用戶名、密碼登錄策略 
  13.  */ 
  14. function LocalStragegy() { 
  15.   this.login = ({ username, password }) => { 
  16.     console.log(username, password); 
  17.     // authenticating with username and password...  
  18.   } 
  19.  
  20. /** 
  21.  * 手機(jī)號(hào)、驗(yàn)證碼登錄策略 
  22.  */ 
  23. function PhoneStragety() { 
  24.   this.login = ({ phone, verifyCode }) => { 
  25.     console.log(phone, verifyCode); 
  26.     // authenticating with hone and verifyCode...  
  27.   } 
  28.  
  29. /** 
  30.  * 第三方社交登錄策略 
  31.  */ 
  32. function SocialStragety() { 
  33.   this.login = ({ id, secret }) => { 
  34.     console.log(id, secret); 
  35.     // authenticating with id and secret...  
  36.   } 
  37.  
  38. const loginController = new LoginController(); 
  39.  
  40. // 調(diào)用用戶名、密碼登錄接口,使用LocalStrategy 
  41. app.use('/login/local'function (req, res) { 
  42.   loginController.setStrategy(new LocalStragegy()); 
  43.   loginController.login(req.body); 
  44. }); 
  45.  
  46. // 調(diào)用手機(jī)、驗(yàn)證碼登錄接口,使用PhoneStrategy 
  47. app.use('/login/phone'function (req, res) { 
  48.   loginController.setStrategy(new PhoneStragety()); 
  49.   loginController.login(req.body); 
  50. }); 
  51.  
  52. // 調(diào)用社交登錄接口,使用SocialStrategy 
  53. app.use('/login/social'function (req, res) { 
  54.   loginController.setStrategy(new SocialStragety()); 
  55.   loginController.login(req.body); 
  56. }); 

從以上示例可以得出使用策略模式有以下優(yōu)勢:

  1. 方便在運(yùn)行時(shí)切換算法和策略
  2. 代碼更簡潔,避免使用大量的條件判斷
  3. 關(guān)注分離,每個(gè)strategy類控制自己的算法邏輯,strategy和其使用者之間也相互獨(dú)立

2. 迭代器模式(Iterator Pattern)

ES6中的迭代器 Iterator 相信大家都不陌生,迭代器用于遍歷容器(集合)并訪問容器中的元素,而且無論容器的數(shù)據(jù)結(jié)構(gòu)是什么(Array、Set、Map等),迭代器的接口都應(yīng)該是一樣的,都需要遵循 迭代器協(xié)議。

迭代器模式解決了以下問題:

  1. 提供一致的遍歷各種數(shù)據(jù)結(jié)構(gòu)的方式,而不用了解數(shù)據(jù)的內(nèi)部結(jié)構(gòu)
  2. 提供遍歷容器(集合)的能力而無需改變?nèi)萜鞯慕涌?/li>

一個(gè)迭代器通常需要實(shí)現(xiàn)以下接口:

  • hasNext():判斷迭代是否結(jié)束,返回Boolean
  • next():查找并返回下一個(gè)元素

為Javascript的數(shù)組實(shí)現(xiàn)一個(gè)迭代器可以這么寫:

  1. const item = [1, 'red'false, 3.14]; 
  2.  
  3. function Iterator(items) { 
  4.   this.items = items; 
  5.   this.index = 0; 
  6.  
  7. Iterator.prototype = { 
  8.   hasNext: function () { 
  9.     return this.index < this.items.length; 
  10.   }, 
  11.   nextfunction () { 
  12.     return this.items[this.index++]; 
  13.   } 

驗(yàn)證一下迭代器是否工作:

  1. const iterator = new Iterator(item);  
  2.   
  3. while(iterator.hasNext()){  
  4.   console.log(iterator.next());  
  5. }  

輸出:

  1. 1, red, false, 3.14 

ES6提供了更簡單的迭代循環(huán)語法 for...of,使用該語法的前提是操作對(duì)象需要實(shí)現(xiàn) 可迭代協(xié)議(The iterable protocol),簡單說就是該對(duì)象有個(gè)Key為 Symbol.iterator 的方法,該方法返回一個(gè)iterator對(duì)象。

比如我們實(shí)現(xiàn)一個(gè) Range 類用于在某個(gè)數(shù)字區(qū)間進(jìn)行迭代:

  1. function Range(start, end) { 
  2.   return { 
  3.     [Symbol.iterator]: function () { 
  4.       return { 
  5.         next() { 
  6.           if (start < end) { 
  7.             return { value: start++, done: false }; 
  8.           } 
  9.           return { done: true, value: end }; 
  10.         } 
  11.       } 
  12.     } 
  13.   } 

驗(yàn)證一下:

  1. for (num of Range(1, 5)) { 
  2.   console.log(num); 

輸出:

  1. 1, 2, 3, 4 

3. 觀察者模式(Observer Pattern)

觀察者模式又稱發(fā)布訂閱模式(Publish/Subscribe Pattern),是我們經(jīng)常接觸到的設(shè)計(jì)模式,日常生活中的應(yīng)用也比比皆是,比如你訂閱了某個(gè)博主的頻道,當(dāng)有內(nèi)容更新時(shí)會(huì)收到推送;又比如JavaScript中的事件訂閱響應(yīng)機(jī)制。觀察者模式的思想用一句話描述就是:被觀察對(duì)象(subject)維護(hù)一組觀察者(observer),當(dāng)被觀察對(duì)象狀態(tài)改變時(shí),通過調(diào)用觀察者的某個(gè)方法將這些變化通知到觀察者。

比如給DOM元素綁定事件的 addEventListener() 方法:

  1. target.addEventListener(type, listener [, options]); 

Target就是被觀察對(duì)象Subject,listener就是觀察者Observer。

觀察者模式中Subject對(duì)象一般需要實(shí)現(xiàn)以下API:

  • subscribe(): 接收一個(gè)觀察者observer對(duì)象,使其訂閱自己
  • unsubscribe(): 接收一個(gè)觀察者observer對(duì)象,使其取消訂閱自己
  • fire(): 觸發(fā)事件,通知到所有觀察者

用JavaScript手動(dòng)實(shí)現(xiàn)觀察者模式:

  1. // 被觀察者 
  2. function Subject() { 
  3.   this.observers = []; 
  4.  
  5. Subject.prototype = { 
  6.   // 訂閱 
  7.   subscribe: function (observer) { 
  8.     this.observers.push(observer); 
  9.   }, 
  10.   // 取消訂閱 
  11.   unsubscribe: function (observerToRemove) { 
  12.     this.observers = this.observers.filter(observer => { 
  13.       return observer !== observerToRemove; 
  14.     }) 
  15.   }, 
  16.   // 事件觸發(fā) 
  17.   fire: function () { 
  18.     this.observers.forEach(observer => { 
  19.       observer.call(); 
  20.     }); 
  21.   } 

驗(yàn)證一下訂閱是否成功:

  1. const subject = new Subject(); 
  2.  
  3. function observer1() { 
  4.   console.log('Observer 1 Firing!'); 
  5.  
  6.  
  7. function observer2() { 
  8.   console.log('Observer 2 Firing!'); 
  9.  
  10. subject.subscribe(observer1); 
  11. subject.subscribe(observer2); 
  12. subject.fire(); 

輸出:

  1. Observer 1 Firing!  
  2. Observer 2 Firing! 

驗(yàn)證一下取消訂閱是否成功:

  1. subject.unsubscribe(observer2); 
  2. subject.fire(); 

輸出:

  1. Observer 1 Firing! 

4. 中介者模式(Mediator Pattern)

在中介者模式中,中介者(Mediator)包裝了一系列對(duì)象相互作用的方式,使得這些對(duì)象不必直接相互作用,而是由中介者協(xié)調(diào)它們之間的交互,從而使它們可以松散偶合。當(dāng)某些對(duì)象之間的作用發(fā)生改變時(shí),不會(huì)立即影響其他的一些對(duì)象之間的作用,保證這些作用可以彼此獨(dú)立的變化。

中介者模式和觀察者模式有一定的相似性,都是一對(duì)多的關(guān)系,也都是集中式通信,不同的是中介者模式是處理同級(jí)對(duì)象之間的交互,而觀察者模式是處理Observer和Subject之間的交互。中介者模式有些像婚戀中介,相親對(duì)象剛開始并不能直接交流,而是要通過中介去篩選匹配再?zèng)Q定誰和誰見面。中介者模式比較常見的應(yīng)用比如聊天室,聊天室里面的人之間并不能直接對(duì)話,而是通過聊天室這一媒介進(jìn)行轉(zhuǎn)發(fā)。一個(gè)簡易的聊天室模型可以實(shí)現(xiàn)如下:

聊天室成員類:

  1. function Member(name) { 
  2.   this.name = name
  3.   this.chatroom = null
  4.  
  5. Member.prototype = { 
  6.   // 發(fā)送消息 
  7.   send: function (message, toMember) { 
  8.     this.chatroom.send(message, this, toMember); 
  9.   }, 
  10.   // 接收消息 
  11.   receive: function (message, fromMember) { 
  12.     console.log(`${fromMember.nameto ${this.name}: ${message}`); 
  13.   } 

聊天室類:

  1. function Chatroom() { 
  2.   this.members = {}; 
  3.  
  4. Chatroom.prototype = { 
  5.   // 增加成員 
  6.   addMember: function (member) { 
  7.     this.members[member.name] = member; 
  8.     member.chatroom = this; 
  9.   }, 
  10.   // 發(fā)送消息 
  11.   send: function (message, fromMember, toMember) { 
  12.     toMember.receive(message, fromMember); 
  13.   } 

測試一下:

  1. const chatroom = new Chatroom(); 
  2. const bruce = new Member('bruce'); 
  3. const frank = new Member('frank'); 
  4.  
  5. chatroom.addMember(bruce); 
  6. chatroom.addMember(frank); 
  7.  
  8. bruce.send('Hey frank', frank); 

輸出:

  1. bruce to frank: hello frank 

這只是一個(gè)最簡單的聊天室模型,真正的聊天室還可以加入更多的功能,比如敏感信息攔截、一對(duì)多聊天、廣播等。得益于中介者模式,Member不需要處理和聊天相關(guān)的復(fù)雜邏輯,而是全部交給Chatroom,有效的實(shí)現(xiàn)了關(guān)注分離。

5. 訪問者模式(Visitor Pattern)

訪問者模式是一種將算法與對(duì)象結(jié)構(gòu)分離的設(shè)計(jì)模式,通俗點(diǎn)講就是:訪問者模式讓我們能夠在不改變一個(gè)對(duì)象結(jié)構(gòu)的前提下能夠給該對(duì)象增加新的邏輯,新增的邏輯保存在一個(gè)獨(dú)立的訪問者對(duì)象中。訪問者模式常用于拓展一些第三方的庫和工具。

訪問者模式的實(shí)現(xiàn)有以下幾個(gè)要素:

  1. Visitor Object:訪問者對(duì)象,擁有一個(gè) visit() 方法
  2. Receiving Object:接收對(duì)象,擁有一個(gè) accept() 方法
  3. visit(receivingObj):用于Visitor接收一個(gè)Receiving Object
  4. accept(visitor):用于Receving Object接收一個(gè)Visitor,并通過調(diào)用Visitor的 visit() 為其提供獲取Receiving Object數(shù)據(jù)的能力

簡單的代碼實(shí)現(xiàn)如下:

Receiving Object:

  1. function Employee(name, salary) { 
  2.   this.name = name
  3.   this.salary = salary; 
  4.  
  5. Employee.prototype = { 
  6.   getSalary: function () { 
  7.     return this.salary; 
  8.   }, 
  9.   setSalary: function (salary) { 
  10.     this.salary = salary; 
  11.   }, 
  12.   accept: function (visitor) { 
  13.     visitor.visit(this); 
  14.   } 

Visitor Object:

  1. function Visitor() { } 
  2.  
  3. Visitor.prototype = { 
  4.   visit: function (employee) { 
  5.     employee.setSalary(employee.getSalary() * 2); 
  6.   } 

驗(yàn)證一下:

  1. const employee = new Employee('bruce', 1000); 
  2. const visitor = new Visitor(); 
  3. employee.accept(visitor); 
  4.  
  5. console.log(employee.getSalary()); 

輸出:

  1. 2000 

本文僅僅初步探討了部分設(shè)計(jì)模式在前端領(lǐng)域的應(yīng)用或者實(shí)現(xiàn),旨在消除大部分同學(xué)心中對(duì)設(shè)計(jì)模式的陌生感和畏懼感?,F(xiàn)有的設(shè)計(jì)模式就有大約50,常見的也有20種左右,所以設(shè)計(jì)模式是一門宏大而深?yuàn)W的學(xué)問需要我們不斷的去學(xué)習(xí)和在實(shí)踐中總結(jié)。本文所涉及到的9種只占了一小部分,未涉及到的模式里面肯定也有對(duì)前端開發(fā)有價(jià)值的,希望以后有機(jī)會(huì)能一一補(bǔ)上。

 

責(zé)任編輯:華軒 來源: segmentfault
相關(guān)推薦

2022-09-14 10:00:12

前端自動(dòng)化測試

2022-02-22 23:39:15

JavaScript編程語言Web

2012-04-01 09:10:17

WEB設(shè)計(jì)師前端

2021-01-26 01:03:36

云原生工具云原生

2021-02-24 11:13:28

網(wǎng)絡(luò)網(wǎng)絡(luò)通信互聯(lián)網(wǎng)

2020-12-09 09:30:57

前端開發(fā)技術(shù)

2021-05-06 08:00:00

人工智能神經(jīng)網(wǎng)絡(luò)深度學(xué)習(xí)

2024-06-14 16:07:41

2012-06-27 09:11:47

2019-07-30 12:05:20

數(shù)據(jù)科學(xué)采樣算法

2012-06-26 10:13:55

2011-04-01 11:16:06

hessian

2018-07-09 11:00:56

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

2023-07-11 07:53:51

CSS效果圖像

2016-01-13 10:09:49

自動(dòng)化運(yùn)維運(yùn)維思想

2018-06-26 12:06:07

數(shù)據(jù)存儲(chǔ)云端云存儲(chǔ)

2011-12-08 09:16:12

2024-04-01 14:14:05

2018-09-29 15:20:08

物聯(lián)網(wǎng)IOT物聯(lián)網(wǎng)設(shè)備

2023-05-25 21:35:00

穩(wěn)定性建設(shè)前端
點(diǎn)贊
收藏

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