偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

設(shè)計模式 | 工作中會用到的單例模式

開發(fā) 前端
單例模式是非常常用的一種設(shè)計模式,工作中我們會用到例如彈窗、音頻管理、消息管理中心、公共工具函數(shù)類等在應(yīng)用中只需要單個實例的場景,這些都和單例模式密不可分。

[[416951]]

本文轉(zhuǎn)載自微信公眾號「DYBOY」,作者DYBOY。轉(zhuǎn)載本文請聯(lián)系DYBOY公眾號。

單例模式是非常常用的一種設(shè)計模式,工作中我們會用到例如彈窗、音頻管理、消息管理中心、公共工具函數(shù)類等在應(yīng)用中只需要單個實例的場景,這些都和單例模式密不可分。

單例模式,很常用也非常重要,將單例模式應(yīng)用于程序開發(fā)設(shè)計,可減少重復(fù)代碼,提升程序效率,同時單例的唯一性也使得數(shù)據(jù)流更加清晰,便于維護(hù)管理。

一、什么是單例模式

單例模式(Singleton Pattern)保證一個類只有一個實例,并提供一個訪問它的全局訪問點。

是不是瞬間想到了 JavaScript 中的全局變量 window、localStorage,它們在全局中提供了訪問點,并且只有唯一實例。

在一些多線程編程語言中,單例模式會涉及到同步鎖的問題,而 JavaScript 是單線程運行的,因此可以暫時忽略線程安全問題。

單例和單身狗類似,直到程序銷毀,整個程序里都找不出第二個和它能夠匹配上的

二、實現(xiàn)單例模式

單例模式從其定義就可以看出,是一個比較簡單的設(shè)計模式,其核心思想是保證唯一實例,因此如下簡單實現(xiàn)一個蒙層功能單例類,一步步完善。

2.1 蒙層單例類

現(xiàn)在的工作環(huán)境下都是基于 ES6 及以上的開發(fā)模式,因此我們直接帶入 class 思想去實現(xiàn),如果有需要了解相關(guān)基礎(chǔ)內(nèi)容的同學(xué)推薦閱讀:《這些JS設(shè)計模式的基礎(chǔ)知識點你都會了嗎?》。

蒙層的功能:

  • 層級最大,覆蓋瀏覽器可視區(qū)域
  • 阻止用戶所有點擊事件
  • 透明蒙層

因此,該蒙層單例的實現(xiàn)如下:

  1. /** 
  2.  * Mask 蒙層單例 
  3.  */ 
  4. class Mask { 
  5.   static instance: Mask; 
  6.   private isShow: boolean; 
  7.   private maskDom: HTMLDivElement; 
  8.  
  9.   static getInstance() { 
  10.     if (!Mask.instance) { 
  11.       Mask.instance = new Mask(); 
  12.     } 
  13.     return Mask.instance; 
  14.   } 
  15.  
  16.   constructor() { 
  17.     this.isShow = false
  18.     this.maskDom = this.init(); 
  19.   } 
  20.  
  21.   /** 
  22.    * 創(chuàng)建蒙層DOM 
  23.    */ 
  24.   private init() { 
  25.     const dom = document.createElement("div"); 
  26.     dom.setAttribute( 
  27.       "style"
  28.       "z-index: 99999; position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: none; pointer-events: all; user-select: none; cursor: not-allowed;" 
  29.     ); 
  30.     document.body.appendChild(dom); 
  31.     return dom; 
  32.   } 
  33.  
  34.   /** 
  35.    * show 顯示蒙層 
  36.    */ 
  37.   public show() { 
  38.     if (this.isShow) return
  39.     this.maskDom.style["display"] = "block"
  40.     this.isShow = true
  41.   } 
  42.  
  43.   /** 
  44.    * hide 隱藏蒙層 
  45.    */ 
  46.   public hide() { 
  47.     if (!this.isShow) return
  48.     this.maskDom.style["display"] = "none"
  49.     this.isShow = false
  50.   } 
  51.  
  52. // 直接導(dǎo)出實例 
  53. export default Mask.getInstance(); 

使用方式:

  1. import Mask from "./utils/Mask"
  2.  
  3. Mask.show(); 
  4. Mask.hide(); 

這種在已開始就創(chuàng)建實例的方式,被稱作“餓漢式單例”,另一種在需要的時候才創(chuàng)建實例的方式被稱作“懶漢式單例”。

因此“餓漢式單例”的缺點就是:類加載時就初始化,浪費內(nèi)存。

不過在現(xiàn)代借助 Webpack 等打包構(gòu)建工具,如果沒有使用到這個組件,也不會將這個組件打包進(jìn)來,另外在 React、Vue 框架按需加載組件的設(shè)計實現(xiàn)下,組件也是按需通過網(wǎng)絡(luò)下載分包組件文件,然后緩存起來,所以浪費內(nèi)存這一缺點可忽略。因此,在 JavaScript 中懶漢式和餓漢式的區(qū)分不大。

推薦使用導(dǎo)出的時候就導(dǎo)出一個實例,例如:

  1. export default Mask.getInstance(); 

2.2 透明蒙層單例

在上述的導(dǎo)出實例中,只能調(diào)用 Mask.getInstance() ,對于其他使用者來說其實已經(jīng)規(guī)避了如何判斷是否是單例類的問題。

另外,如果我們的導(dǎo)出形式是這樣的:

  1. export default Mask; 

那么其他同學(xué)在引用這個組件時候,如果不知道是一個單例類,那他就可能會直接 new Mask() 方式使用,那么就會創(chuàng)建多個不同的實例,失去了單例的效果,為了讓單例類使用的時候能像普通類創(chuàng)建對象的寫法一致,在使用的時候和其他普通類一樣,我們把這個處理方式叫做“透明化”。

為此,稍微改動下構(gòu)造函數(shù)中的判斷:

  1. constructor() { 
  2.   if (Mask.instance) { 
  3.     return Mask.instance; 
  4.   } 
  5.   this.isShow = false
  6.   this.maskDom = this.init(); 
  7.   return Mask.instance = this; 
  8.  
  9. ... 
  10.  
  11. export default Mask; 

使用驗證:

  1. const a = new Mask(); 
  2. a.show(); 
  3. const b = new Mask(); 
  4. b.hide(); 
  5. console.log("是否相等:", a === b); 
  6. // output: 是否相等 true,并且蒙層被隱藏 

如果為了保證類的透明性,使用方式的統(tǒng)一,可以采用在構(gòu)造函數(shù)中預(yù)先判斷是否存在實例的方式來實現(xiàn)。

2.3 單例化工具函數(shù)

通過上述對單例模式的實現(xiàn)和使用,其實可以想到一個問題,單例模式,只需要保證唯一實例即可,而保證唯一實例的方式,是通過一個變量來判斷當(dāng)前實例是否已經(jīng)被創(chuàng)建過,如果已經(jīng)創(chuàng)建了,則直接返回該實例,否則創(chuàng)建后再返回實例。

那么通用的單例模式,應(yīng)該將單例化和類的職責(zé)拆分開。

講到這,對于前面分享的《從“圖片預(yù)加載”認(rèn)識代理設(shè)計模式》中的緩存代理就非常相似了,借助代理模式的思想,用閉包來緩存單例。

單例化緩存工具函數(shù):

  1. export const proxySingleton = (fn) => { 
  2.   let instance; 
  3.   return () => { 
  4.     if (instance) return instance; 
  5.     return instance = new fn(); 
  6.   }; 
  7. }; 

傳入我們之前寫的任意類,類名指向了構(gòu)造函數(shù)

  1. export const singletonMask = proxySingleton(Mask); 

使用的時候:

  1. import { singletonMask } from "./utils/ProxySingleton"
  2.  
  3. const a = singletonMask(); 
  4. a.show(); 
  5. const b = singletonMask(); 
  6. b.hide(); 
  7. console.log("是否相等:", a === b); 
  8. // output: 是否相等 true,并且蒙層被隱藏 

這樣我們就將單例化和創(chuàng)建蒙層類職責(zé)拆分,遵循單一職責(zé)原則。

2.4 ES6 export實例 import單例

舉一反三,是不是在 ES6 中直接 export 一個實例是否就可以看作是單例了吶?

  1. export default new Mask(); 

import 引入是采用的單例(Singleton)模式,多次用 import 引入同一個模塊時,只會引入一次該模塊的實例 —— 《ECMAScript 6 入門》

因此,如果要通用的單例對象,我們可以直接在 export 的時候,就導(dǎo)出實例。

之前我們研究過 EventEmitter3 事件觸發(fā)器的原理,為了讓之在全局只有一個實例,我們的使用方法如下:

  1. // ./utils/eventEmitter.ts 
  2. import EventEmitter from 'eventemitter3'
  3.  
  4. export default new EventEmitter(); 

這樣導(dǎo)出的 eventEmitter 就是一個單例,唯一,且全局可訪問。

三、總結(jié)

單例模式在工作中經(jīng)常用到,當(dāng)我們有意識地使用單例管理具有唯一屬性的實例,將會使得程序更容易管理維護(hù)。

結(jié)合 ES6 的 import 和 export 關(guān)鍵詞,單例模式的應(yīng)用也變得更加簡便。 

在實現(xiàn)單例中,我們有將單例和蒙層類功能拆分開,也有合在一起的,這取決于在你的項目中想要如何設(shè)計,如果單例并非是大面積的組件套用,其實還是推薦合在一起,有助于后續(xù)在單文件中維護(hù)整個功能類。

 

責(zé)任編輯:武曉燕 來源: DYBOY
相關(guān)推薦

2021-10-27 17:57:35

設(shè)計模式場景

2021-02-01 10:01:58

設(shè)計模式 Java單例模式

2021-04-18 21:07:32

門面模式設(shè)計

2021-03-02 08:50:31

設(shè)計單例模式

2021-04-14 09:02:22

模式 設(shè)計建造者

2022-02-06 22:30:36

前端設(shè)計模式

2013-11-26 16:20:26

Android設(shè)計模式

2016-03-28 10:23:11

Android設(shè)計單例

2022-06-07 08:55:04

Golang單例模式語言

2024-02-04 12:04:17

2015-09-06 11:07:52

C++設(shè)計模式單例模式

2024-12-11 08:20:57

設(shè)計模式源碼

2021-09-07 10:44:35

異步單例模式

2022-09-29 08:39:37

架構(gòu)

2023-08-03 08:01:27

單例模式結(jié)構(gòu)開發(fā)

2022-03-29 07:52:07

設(shè)計模式單例設(shè)計模式java

2024-03-06 13:19:19

工廠模式Python函數(shù)

2012-10-30 09:44:33

敏捷開發(fā)

2011-03-16 10:13:31

java單例模式

2021-02-07 23:58:10

單例模式對象
點贊
收藏

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