真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

web前端需要了解的設(shè)計模式有哪些

這篇文章主要講解了“web前端需要了解的設(shè)計模式有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“web前端需要了解的設(shè)計模式有哪些”吧!

10年積累的網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先做網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有安寧免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

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

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

設(shè)計模式的類型

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

  1. 結(jié)構(gòu)型模式(Structural Patterns): 通過識別系統(tǒng)中組件間的簡單關(guān)系來簡化系統(tǒng)的設(shè)計。

  2. 創(chuàng)建型模式(Creational Patterns):  處理對象的創(chuàng)建,根據(jù)實際情況使用合適的方式創(chuàng)建對象。常規(guī)的對象創(chuàng)建方式可能會導(dǎo)致設(shè)計上的問題,或增加設(shè)計的復(fù)雜度。創(chuàng)建型模式通過以某種方式控制對象的創(chuàng)建來解決問題。

  3. 行為型模式(Behavioral Patterns): 用于識別對象之間常見的交互模式并加以實現(xiàn),如此,增加了這些交互的靈活性。

以上定義非常的抽象和晦澀,對于我們初學(xué)者并沒有太多幫助,要了解這些設(shè)計模式真正的作用和價值還是需要通過實踐去加以理解。

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

1. 外觀模式(Facade Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

// 綁定事件 function addEvent(element, event, handler) {   if (element.addEventListener) {     element.addEventListener(event, handler, false);   } else if (element.attachEvent) {     element.attachEvent('on' + event, handler);   } else {     element['on' + event] = fn;   } }  // 取消綁定 function removeEvent(element, event, handler) {   if (element.removeEventListener) {     element.removeEventListener(event, handler, false);   } else if (element.detachEvent) {     element.detachEvent('on' + event, handler);   } else {     element['on' + event] = null;   } }

2. 代理模式(Proxy Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 增加對一個對象的訪問控制

  3. 當(dāng)訪問一個對象的過程中需要增加額外的邏輯

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

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Real Subject:真實對象

  3. Proxy:代理對象

  4. Subject接口:Real Subject 和 Proxy都需要實現(xiàn)的接口,這樣Proxy才能被當(dāng)成Real Subject的“替身”使用

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

StockPriceAPI:

function StockPriceAPI() {   // Subject Interface實現(xiàn)   this.getValue = function (stock, callback) {     console.log('Calling external API ... ');     setTimeout(() => {       switch (stock) {         case 'GOOGL':           callback('$1265.23');           break;         case 'AAPL':           callback('$287.05');           break;         case 'MSFT':           callback('$173.70');           break;         default:           callback('');       }     }, 2000);   } }

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

StockPriceAPIProxy:

function StockPriceAPIProxy() {   // 緩存對象   this.cache = {};   // 真實API對象   this.realAPI = new StockPriceAPI();   // Subject Interface實現(xiàn)   this.getValue = function (stock, callback) {     const cachedPrice = this.cache[stock];     if (cachedPrice) {       console.log('Got price from cache');       callback(cachedPrice);     } else {       this.realAPI.getValue(stock, (price) => {         this.cache[stock] = price;         callback(price);       });     }   } }

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

測試一下:

const api = new StockPriceAPIProxy(); api.getValue('GOOGL', (price) => { console.log(price) }); api.getValue('AAPL', (price) => { console.log(price) }); api.getValue('MSFT', (price) => { console.log(price) });  setTimeout(() => {   api.getValue('GOOGL', (price) => { console.log(price) });   api.getValue('AAPL', (price) => { console.log(price) });   api.getValue('MSFT', (price) => { console.log(price) }); }, 3000)

輸出:

Calling external API ...  Calling external API ...  Calling external API ...  $1265.23 $287.05 $173.70 Got price from cache $1265.23 Got price from cache $287.05 Got price from cache $173.70

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

1. 工廠模式(Factory Pattern)

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

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

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

// 汽車構(gòu)造函數(shù) function SuzukiCar(color) {   this.color = color;   this.brand = 'Suzuki'; }  // 汽車構(gòu)造函數(shù) function HondaCar(color) {   this.color = color;   this.brand = 'Honda'; }  // 汽車構(gòu)造函數(shù) function BMWCar(color) {   this.color = color;   this.brand = 'BMW'; }  // 汽車品牌枚舉 const BRANDS = {   suzuki: 1,   honda: 2,   bmw: 3 }  /**  * 汽車工廠  */ function CarFactory() {   this.create = function (brand, color) {     switch (brand) {       case BRANDS.suzuki:         return new SuzukiCar(color);       case BRANDS.honda:         return new HondaCar(color);       case BRANDS.bmw:         return new BMWCar(color);       default:         break;     }   } }

測試一下:

const carFactory = new CarFactory(); const cars = [];  cars.push(carFactory.create(BRANDS.suzuki, 'brown')); cars.push(carFactory.create(BRANDS.honda, 'grey')); cars.push(carFactory.create(BRANDS.bmw, 'red'));  function say() {   console.log(`Hi, I am a ${this.color} ${this.brand} car`); }  for (const car of cars) {   say.call(car); }

輸出:

Hi, I am a brown Suzuki car Hi, I am a grey Honda car Hi, I am a red BMW car

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

2. 單例模式(Singleton Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

  1. 如何確定Class只有一個實例?

  2. 如何簡便的訪問Class的唯一實例?

  3. Class如何控制實例化的過程?

  4. 如何將Class的實例個數(shù)限制為1?

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

  1. 隱藏Class的構(gòu)造函數(shù),避免多次實例化

  2. 通過暴露一個 getInstance() 方法來創(chuàng)建/獲取唯一實例

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

// 單例構(gòu)造器 const FooServiceSingleton = (function () {   // 隱藏的Class的構(gòu)造函數(shù)   function FooService() {}    // 未初始化的單例對象   let fooService;    return {     // 創(chuàng)建/獲取單例對象的函數(shù)     getInstance: function () {       if (!fooService) {         fooService = new FooService();       }       return fooService;     }   } })();

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

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

const fooService1 = FooServiceSingleton.getInstance(); const fooService2 = FooServiceSingleton.getInstance();  console.log(fooService1 === fooService2); // true

三. 行為型模式(Behavioral Patterns)

1. 策略模式(Strategy Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

/**  * 登錄控制器  */ function LoginController() {   this.strategy = undefined;   this.setStrategy = function (strategy) {     this.strategy = strategy;     this.login = this.strategy.login;   } }  /**  * 用戶名、密碼登錄策略  */ function LocalStragegy() {   this.login = ({ username, password }) => {     console.log(username, password);     // authenticating with username and password...    } }  /**  * 手機(jī)號、驗證碼登錄策略  */ function PhoneStragety() {   this.login = ({ phone, verifyCode }) => {     console.log(phone, verifyCode);     // authenticating with hone and verifyCode...    } }  /**  * 第三方社交登錄策略  */ function SocialStragety() {   this.login = ({ id, secret }) => {     console.log(id, secret);     // authenticating with id and secret...    } }  const loginController = new LoginController();  // 調(diào)用用戶名、密碼登錄接口,使用LocalStrategy app.use('/login/local', function (req, res) {   loginController.setStrategy(new LocalStragegy());   loginController.login(req.body); });  // 調(diào)用手機(jī)、驗證碼登錄接口,使用PhoneStrategy app.use('/login/phone', function (req, res) {   loginController.setStrategy(new PhoneStragety());   loginController.login(req.body); });  // 調(diào)用社交登錄接口,使用SocialStrategy app.use('/login/social', function (req, res) {   loginController.setStrategy(new SocialStragety());   loginController.login(req.body); });

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

  1. 方便在運(yùn)行時切換算法和策略

  2. 代碼更簡潔,避免使用大量的條件判斷

  3. 關(guān)注分離,每個strategy類控制自己的算法邏輯,strategy和其使用者之間也相互獨(dú)立

2. 迭代器模式(Iterator Pattern)

web前端需要了解的設(shè)計模式有哪些

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)萜鞯慕涌?/p>

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

  • hasNext():判斷迭代是否結(jié)束,返回Boolean

  • next():查找并返回下一個元素

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

const item = [1, 'red', false, 3.14];  function Iterator(items) {   this.items = items;   this.index = 0; }  Iterator.prototype = {   hasNext: function () {     return this.index < this.items.length;   },   next: function () {     return this.items[this.index++];   } }

驗證一下迭代器是否工作:

const iterator = new Iterator(item);    while(iterator.hasNext()){    console.log(iterator.next());  }

輸出:

1, red, false, 3.14

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

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

function Range(start, end) {   return {     [Symbol.iterator]: function () {       return {         next() {           if (start < end) {             return { value: start++, done: false };           }           return { done: true, value: end };         }       }     }   } }

驗證一下:

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

輸出:

1, 2, 3, 4

3. 觀察者模式(Observer Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

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

Target就是被觀察對象Subject,listener就是觀察者Observer。

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

  • subscribe(): 接收一個觀察者observer對象,使其訂閱自己

  • unsubscribe(): 接收一個觀察者observer對象,使其取消訂閱自己

  • fire(): 觸發(fā)事件,通知到所有觀察者

用JavaScript手動實現(xiàn)觀察者模式:

// 被觀察者 function Subject() {   this.observers = []; }  Subject.prototype = {   // 訂閱   subscribe: function (observer) {     this.observers.push(observer);   },   // 取消訂閱   unsubscribe: function (observerToRemove) {     this.observers = this.observers.filter(observer => {       return observer !== observerToRemove;     })   },   // 事件觸發(fā)   fire: function () {     this.observers.forEach(observer => {       observer.call();     });   } }

驗證一下訂閱是否成功:

const subject = new Subject();  function observer1() {   console.log('Observer 1 Firing!'); }   function observer2() {   console.log('Observer 2 Firing!'); }  subject.subscribe(observer1); subject.subscribe(observer2); subject.fire();

輸出:

Observer 1 Firing!  Observer 2 Firing!

驗證一下取消訂閱是否成功:

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

輸出:

Observer 1 Firing!

4. 中介者模式(Mediator Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

聊天室成員類:

function Member(name) {   this.name = name;   this.chatroom = null; }  Member.prototype = {   // 發(fā)送消息   send: function (message, toMember) {     this.chatroom.send(message, this, toMember);   },   // 接收消息   receive: function (message, fromMember) {     console.log(`${fromMember.name} to ${this.name}: ${message}`);   } }

聊天室類:

function Chatroom() {   this.members = {}; }  Chatroom.prototype = {   // 增加成員   addMember: function (member) {     this.members[member.name] = member;     member.chatroom = this;   },   // 發(fā)送消息   send: function (message, fromMember, toMember) {     toMember.receive(message, fromMember);   } }

測試一下:

const chatroom = new Chatroom(); const bruce = new Member('bruce'); const frank = new Member('frank');  chatroom.addMember(bruce); chatroom.addMember(frank);  bruce.send('Hey frank', frank);

輸出:

bruce to frank: hello frank

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

5. 訪問者模式(Visitor Pattern)

web前端需要了解的設(shè)計模式有哪些

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

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

  1. Visitor Object:訪問者對象,擁有一個 visit() 方法

  2. Receiving Object:接收對象,擁有一個 accept() 方法

  3. visit(receivingObj):用于Visitor接收一個Receiving Object

  4. accept(visitor):用于Receving Object接收一個Visitor,并通過調(diào)用Visitor的 visit()  為其提供獲取Receiving Object數(shù)據(jù)的能力

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

Receiving Object:

function Employee(name, salary) {   this.name = name;   this.salary = salary; }  Employee.prototype = {   getSalary: function () {     return this.salary;   },   setSalary: function (salary) {     this.salary = salary;   },   accept: function (visitor) {     visitor.visit(this);   } }

Visitor Object:

function Visitor() { }  Visitor.prototype = {   visit: function (employee) {     employee.setSalary(employee.getSalary() * 2);   } }

驗證一下:

const employee = new Employee('bruce', 1000); const visitor = new Visitor(); employee.accept(visitor);  console.log(employee.getSalary());

輸出:

2000

感謝各位的閱讀,以上就是“web前端需要了解的設(shè)計模式有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對web前端需要了解的設(shè)計模式有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!


網(wǎng)站欄目:web前端需要了解的設(shè)計模式有哪些
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/ppsdsg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部