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

掌握前端5大常用設(shè)計(jì)模式,瞬間高大上

開發(fā) 前端
今天主要介紹一下我們平常會經(jīng)常用到的設(shè)計(jì)模式,設(shè)計(jì)模式總的來說有23種,而設(shè)計(jì)模式在前端中又該怎么運(yùn)用呢,接下來主要對比較前端中常見的設(shè)計(jì)模式做一個(gè)介紹。

今天主要介紹一下我們平常會經(jīng)常用到的設(shè)計(jì)模式,設(shè)計(jì)模式總的來說有23種,而設(shè)計(jì)模式在前端中又該怎么運(yùn)用呢,接下來主要對比較前端中常見的設(shè)計(jì)模式做一個(gè)介紹。

[[261215]]

設(shè)計(jì)模式的定義

設(shè)計(jì)模式是在面向?qū)ο筌浖O(shè)計(jì)過程中針對特定問題的簡潔而優(yōu)雅的解決方案。在不同的編程語言中,對設(shè)計(jì)模式的實(shí)現(xiàn)其實(shí)是可能會有區(qū)別的。比如java和javascript,在Java這種靜態(tài)編譯型語言中,無法動態(tài)地給已存在的對象添加職責(zé),所以一般通過包裝類的方式來實(shí)現(xiàn)裝飾者模式。但在JavaScript這種動態(tài)解釋型語言中,給對象動態(tài)添加職責(zé)是再簡單不過的事情。這就造成了JavaScript語言的裝飾者模式不再關(guān)注于給對象動態(tài)添加職責(zé),而是關(guān)注于給函數(shù)動態(tài)添加職責(zé)。本篇將介紹以下幾個(gè)比較常見的設(shè)計(jì)模式:

  • 工廠模式
  • 單例模式
  • 代理模式
  • 觀察者模式
  • 策略模式

一、工廠模式

工廠模式是用來創(chuàng)建對象的一種最常用的設(shè)計(jì)模式,不暴露創(chuàng)建對象的具體邏輯,而是將將邏輯封裝在一個(gè)函數(shù)中,那么這個(gè)函數(shù)就可以被視為一個(gè)工廠,工廠模式根據(jù)抽象程度的不同可以分為:簡單工廠,工廠方法和抽象工廠,接下來,將對簡單工廠和工廠方法在JavaScript中的運(yùn)用舉個(gè)簡單的例子:

1. 簡單工廠

簡單工廠模式又叫靜態(tài)工廠模式,由一個(gè)工廠對象決定創(chuàng)建某一種產(chǎn)品對象類的實(shí)例,主要用來創(chuàng)建同一類對象

比如說,在實(shí)際的項(xiàng)目中,我們常常需要根據(jù)用戶的權(quán)限來渲染不同的頁面,高級權(quán)限的用戶所擁有的頁面有些是無法被低級權(quán)限的用戶所查看,所以我們可以在不同權(quán)限等級用戶的構(gòu)造函數(shù)中,保存該用戶能夠看到的頁面。

  1. let UserFactory = function (role) { 
  2.  function SuperAdmin() { 
  3.  this.name = "超級管理員"
  4.  this.viewPage = ['首頁', '用戶管理', '訂單管理', '應(yīng)用管理', '權(quán)限管理'] 
  5.  } 
  6.  function Admin() { 
  7.  this.name = "管理員"
  8.  this.viewPage = ['首頁', '訂單管理', '應(yīng)用管理'] 
  9.  } 
  10.  function NormalUser() { 
  11.  this.name = '普通用戶'
  12.  this.viewPage = ['首頁', '訂單管理'] 
  13.  } 
  14.  switch (role) { 
  15.  case 'superAdmin': 
  16.  return new SuperAdmin(); 
  17.  break; 
  18.  case 'admin': 
  19.  return new Admin(); 
  20.  break; 
  21.  case 'user': 
  22.  return new NormalUser(); 
  23.  break; 
  24.  default: 
  25.  throw new Error('參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin、admin、user'); 
  26.  } 
  27. //調(diào)用 
  28. let superAdmin = UserFactory('superAdmin'); 
  29. let admin = UserFactory('admin')  
  30. let normalUser = UserFactory('user') 

總結(jié):在上面的例子中,UserFactory就是一個(gè)簡單工廠,在該函數(shù)中有3個(gè)構(gòu)造函數(shù)分別對應(yīng)不同的權(quán)限的用戶,當(dāng)我們調(diào)用工廠函數(shù)時(shí),只需要傳遞superAdmin, admin, user這三個(gè)可選參數(shù)中的一個(gè)獲取對應(yīng)的實(shí)例對象

  • 優(yōu)點(diǎn):簡單工廠的優(yōu)點(diǎn)在于,你只需要一個(gè)正確的參數(shù),就可以獲取到你所需要的對象,而無需知道其創(chuàng)建的具體細(xì)節(jié);
  • 缺點(diǎn):在函數(shù)內(nèi)包含了所有對象的創(chuàng)建邏輯(構(gòu)造函數(shù))和判斷邏輯的代碼,每增加新的構(gòu)造函數(shù)還需要修改判斷邏輯代碼,我們的對象不是上面的3個(gè)而是30個(gè)或更多時(shí),這個(gè)函數(shù)會成為一個(gè)龐大的超級函數(shù),便得難以維護(hù),簡單工廠只能作用于創(chuàng)建的對象數(shù)量較少,對象的創(chuàng)建邏輯不復(fù)雜時(shí)使用;

2. 工廠方法

工廠方法模式的本意是將實(shí)際創(chuàng)建對象的工作推遲到子類中,這樣核心類就變成了抽象類,但是在JavaScript中很難像傳統(tǒng)面向?qū)ο竽菢尤?shí)現(xiàn)創(chuàng)建抽象類,所以在JavaScript中我們只需要參考它的核心思想即可,我們可以將工廠方法看作是一個(gè)實(shí)例化對象的工廠類

比如說上面的例子,我們用工廠方法可以這樣寫,工廠方法我們只把它看作是一個(gè)實(shí)例化對象的工廠,它只做實(shí)例化對象這一件事情,我們采用安全模式創(chuàng)建對象

  1. //安全模式創(chuàng)建的工廠方法函數(shù) 
  2. let UserFactory = function(role) { 
  3.  if(this instanceof UserFactory) { 
  4.  var s = new this[role](); 
  5.  return s; 
  6.  } else { 
  7.  return new UserFactory(role); 
  8.  } 
  9. //工廠方法函數(shù)的原型中設(shè)置所有對象的構(gòu)造函數(shù) 
  10. UserFactory.prototype = { 
  11.  SuperAdmin: function() { 
  12.  this.name = "超級管理員"
  13.  this.viewPage = ['首頁', '用戶管理', '訂單管理', '應(yīng)用管理', '權(quán)限管理'] 
  14.  }, 
  15.  Admin: function() { 
  16.  this.name = "管理員"
  17.  this.viewPage = ['首頁', '訂單管理', '應(yīng)用管理'] 
  18.  }, 
  19.  NormalUser: function() { 
  20.  this.name = '普通用戶'
  21.  this.viewPage = ['首頁', '訂單管理'] 
  22.  } 
  23. //調(diào)用 
  24. let superAdmin = UserFactory('SuperAdmin'); 
  25. let admin = UserFactory('Admin')  
  26. let normalUser = UserFactory('NormalUser') 

總結(jié):在簡單工廠中,如果我們新增加一個(gè)用戶類型,需要修改兩個(gè)地方的代碼,一個(gè)是增加新的用戶構(gòu)造函數(shù),一個(gè)是在邏輯判斷中增加對新的用戶的判斷,而在抽象工廠方法中,我們只需要在UserFactory.prototype中添加就可以啦。

二、單例模式

定義:是保證一個(gè)類只有一個(gè)實(shí)例,并且提供一個(gè)訪問它的全局訪問點(diǎn)。

需求:一些對象我們往往只需要一個(gè),比如線程池、全局緩存、瀏覽器中的window對象、登錄浮窗等。

實(shí)現(xiàn):用一個(gè)變量標(biāo)識當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對象,如果是,則在下一次獲取這個(gè)類的實(shí)例時(shí),直接返回之前創(chuàng)建的對象。

優(yōu)點(diǎn):

  • 可以用來劃分命名空間,減少全局變量的數(shù)量
  • 可以被實(shí)例化,且實(shí)例化一次,再次實(shí)例化生成的也是***個(gè)實(shí)例

下面舉個(gè)例子,在js中,我們可以使用閉包來創(chuàng)建實(shí)現(xiàn)這種模式:

  1. var single = (function(){ 
  2.  var unique; 
  3.  function getInstance(){ 
  4.  // 如果該實(shí)例存在,則直接返回,否則就對其實(shí)例化 
  5.  if( unique === undefined ){ 
  6.  unique = new Construct(); 
  7.  } 
  8.  return unique; 
  9.  } 
  10.  function Construct(){ 
  11.  // ... 生成單例的構(gòu)造函數(shù)的代碼 
  12.  } 
  13.  return { 
  14.  getInstance : getInstance 
  15.  } 
  16. })(); 

總結(jié):在上面的代碼中,我們可以使用single.getInstance來獲取到單例,并且每次調(diào)用均獲取到同一個(gè)單例,在我們平時(shí)的開發(fā)中,我們也經(jīng)常會用到這種模式,比如當(dāng)我們單擊登錄按鈕的時(shí)候,頁面中會出現(xiàn)一個(gè)登錄框,而這個(gè)浮窗是唯一的,無論單擊多少次登錄按鈕,這個(gè)浮窗只會被創(chuàng)建一次,因此這個(gè)登錄浮窗就適合用單例模式。

三、代理模式

代理模式主要是為其他對象提供一種代理以控制對這個(gè)對象的訪問,主要解決在直接訪問對象時(shí)帶來的問題,比如說:要訪問的對象在遠(yuǎn)程的機(jī)器上,在面向?qū)ο笙到y(tǒng)中,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問),直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩,我們可以在訪問此對象時(shí)加上一個(gè)對此對象的訪問層。

代理模式最基本的形式是對訪問進(jìn)行控制,代理對象和另一個(gè)對象(本體)實(shí)現(xiàn)的是同樣的接口,實(shí)際上工作還是本體在做,它才是負(fù)責(zé)執(zhí)行所分派的任務(wù)的那個(gè)對象或類,代理對象所做的不外乎節(jié)制對本體的訪問,代理對象并不會在另一對象的基礎(chǔ)上添加方法或修改其方法,也不會簡化那個(gè)對象的接口,它實(shí)現(xiàn)的接口與本體完全相同,所有對它進(jìn)行的方法調(diào)用都會被傳遞給本體。

  1. (function(){ 
  2.  // 示例代碼 
  3.   
  4.  // 目標(biāo)對象,是真正被代理的對象 
  5.  function Subject(){} 
  6.  Subject.prototype.request = function(){}; 
  7.   
  8.  /** 
  9.  * 代理對象 
  10.  * @param {Object} realSubject [持有被代理的具體的目標(biāo)對象] 
  11.  */ 
  12.  function Proxy(realSubject){ 
  13.  this.realSubject = readSubject
  14.  } 
  15.  Proxy.prototype.request = function(){ 
  16.  this.realSubject.request(); 
  17.  }; 
  18. }()); 

總結(jié):在上面的代碼中,Proxy可以控制對真正被代理對象的一個(gè)訪問,在代理模式中,比較常見的就是虛擬代理,虛擬代理用于控制對那種創(chuàng)建開銷很大的本體的訪問,它會把本體的實(shí)例化推遲到有方法被調(diào)用的時(shí)候,比如說,現(xiàn)在我們假設(shè)PublicLibrary的實(shí)例化很慢,不能在網(wǎng)頁加載的時(shí)候立即完成,我們可以為其創(chuàng)建一個(gè)虛擬代理,讓它把PublicLibrary的實(shí)例化推遲到必要的時(shí)候,比如說我們在前端中經(jīng)常用到的圖片懶加載,就可以用虛擬代理;

四、觀察者模式

如果大家學(xué)過一些像vue,react這些框架,相信大家對觀察者模式一定很熟悉,現(xiàn)在很多mvvm框架都用到了觀察者模式這個(gè)思想,觀察者模式又叫做發(fā)布—訂閱模式,它定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都將得到通知和更新,觀察者模式提供了一個(gè)訂閱模型,其中對象訂閱事件并在發(fā)生時(shí)得到通知,這種模式是事件驅(qū)動的編程基石,它有利益于良好的面向?qū)ο蟮脑O(shè)計(jì)

定義:對象間的一種一對多的依賴關(guān)系。

需求:當(dāng)一個(gè)對象的狀態(tài)發(fā)生變化時(shí),所有依賴于他的對象都將得到通知。

優(yōu)點(diǎn):時(shí)間上的解耦,對象之間的解耦。

實(shí)現(xiàn):

  • 指定好誰充當(dāng)發(fā)布者;
  • 給發(fā)布者添加一個(gè)緩存列表,用于存放回調(diào)函數(shù)以便通知訂閱者;
  • 發(fā)布消息的時(shí)候,發(fā)布者會遍歷這個(gè)緩存列表,依次觸發(fā)里面存放的訂閱者回調(diào)函數(shù)。

下面舉個(gè)例子,比如我們給頁面中的一個(gè)dom節(jié)點(diǎn)綁定一個(gè)事件,其實(shí)就可以看做是一種觀察者模式:

  1. document.body.addEventListener("click", function() { 
  2.  alert("Hello World") 
  3. },false ) 
  4. document.body.click() //模擬用戶點(diǎn)擊 

總結(jié):在上面的例子中,需要監(jiān)聽用戶點(diǎn)擊 document.body 的動作,但是我們是沒辦法預(yù)知用戶將在什么時(shí)候點(diǎn)擊的,因此我們訂閱了 document.body 的 click 事件,當(dāng) body 節(jié)點(diǎn)被點(diǎn)擊時(shí),body 節(jié)點(diǎn)便會向訂閱者發(fā)布 "Hello World" 消息。

五、策略模式

策略模式指的是定義一些列的算法,把他們一個(gè)個(gè)封裝起來,目的就是將算法的使用與算法的實(shí)現(xiàn)分離開來,避免多重判斷條件,更具有擴(kuò)展性。

下面也是舉個(gè)例子,現(xiàn)在超市有活動,vip為5折,老客戶3折,普通顧客沒折,計(jì)算***需要支付的金額,如果不使用策略模式,我們的代碼可能和下面一樣:

  1. function Price(personType, price) { 
  2.  //vip 5 折 
  3.  if (personType == 'vip') { 
  4.  return price * 0.5; 
  5.  }  
  6.  else if (personType == 'old'){ //老客戶 3 折 
  7.  return price * 0.3; 
  8.  } else { 
  9.  return price; //其他都全價(jià) 
  10.  } 

在上面的代碼中,我們需要很多個(gè)判斷,如果有很多優(yōu)惠,我們又需要添加很多判斷,這里已經(jīng)違背了剛才說的設(shè)計(jì)模式的六大原則中的開閉原則了,如果使用策略模式,我們的代碼可以這樣寫:

  1. // 對于vip客戶 
  2. function vipPrice() { 
  3.  this.discount = 0.5; 
  4.   
  5. vipPrice.prototype.getPrice = function(price) { 
  6.  return price * this.discount; 
  7. // 對于老客戶 
  8. function oldPrice() { 
  9.  this.discount = 0.3; 
  10.   
  11. oldPrice.prototype.getPrice = function(price) { 
  12.  return price * this.discount; 
  13. // 對于普通客戶 
  14. function Price() { 
  15.  this.discount = 1
  16.   
  17. Price.prototype.getPrice = function(price) { 
  18.  return price ; 
  19. // 上下文,對于客戶端的使用 
  20. function Context() { 
  21.  this.name = ''
  22.  this.strategy = null
  23.  this.price = 0
  24.   
  25. Context.prototype.set = function(name, strategy, price) { 
  26.  this.name = name; 
  27.  this.strategy = strategy; 
  28.  this.price = price; 
  29. Context.prototype.getResult = function() { 
  30.  console.log(this.name + ' 的結(jié)賬價(jià)為: ' + this.strategy.getPrice(this.price)); 
  31. var context = new Context(); 
  32. var vip = new vipPrice(); 
  33. context.set ('vip客戶', vip, 200); 
  34. context.getResult(); // vip客戶 的結(jié)賬價(jià)為: 100 
  35. var old = new oldPrice(); 
  36. context.set ('老客戶', old, 200); 
  37. context.getResult(); // 老客戶 的結(jié)賬價(jià)為: 60 
  38. var Price = new Price(); 
  39. context.set ('普通客戶', Price, 200); 
  40. context.getResult(); // 普通客戶 的結(jié)賬價(jià)為: 200 

總結(jié):在上面的代碼中,通過策略模式,使得客戶的折扣與算法解藕,又使得修改跟擴(kuò)展能獨(dú)立的進(jìn)行,不影到客戶端或其他算法的使用。

當(dāng)我們的代碼中有很多個(gè)判斷分支,每一個(gè)條件分支都會引起該“類”的特定行為以不同的方式作出改變,這個(gè)時(shí)候就可以使用策略模式,可以改進(jìn)我們代碼的質(zhì)量,也更好的可以進(jìn)行單元測試。

責(zé)任編輯:趙寧寧 來源: 今日頭條
相關(guān)推薦

2020-05-06 16:32:18

for循環(huán)Python迭代

2023-12-26 08:20:40

2024-12-25 12:00:00

C++解包代碼

2024-05-07 10:19:25

前端裝飾器計(jì)算

2024-08-12 16:16:29

2020-09-11 09:35:18

前端JavaScript策略模式

2012-10-29 11:16:13

2009-10-29 09:06:26

VB.NET Web

2022-02-11 10:22:48

模版模式語言

2022-02-15 22:45:00

前端設(shè)計(jì)模式

2022-01-19 08:21:12

設(shè)計(jì)裝飾器模式

2016-06-07 13:53:43

ios蘋果概念

2020-05-25 10:20:19

享元模式場景

2022-02-06 22:30:36

前端設(shè)計(jì)模式

2022-11-30 17:05:33

代碼程序場景

2022-11-14 08:44:56

前端門面模式接口

2020-11-10 16:01:25

程序員設(shè)計(jì)模式技術(shù)

2022-02-13 23:33:24

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

2022-01-29 22:12:35

前端模式觀察者

2017-11-06 05:59:45

點(diǎn)贊
收藏

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