最近再準備秋招,然後順便把過去空白的設計模式相關概念補一補,這些內容都是從《JavaScript設計模式與開發實踐》一書中整理出來的

(1)單例模式

定義:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。

適用場景:一個單一物件。比如:登入彈窗,無論點選多少次,登入彈窗只會被建立一次

簡單版實現方法:判斷例項存在與否,如果存在則直接返回,如果不存在就建立了再返回,這就確保了一個類只有一個例項物件。 拓展:

透明的單例模式:解決了簡單單例的不透明性,使用者需知道其是一個單例物件才能進行獲取

代理實現單例模式:建立單例和管理單例邏輯分開,管理單例邏輯放在代理類中

惰性單例技術:合適的時候才建立物件,並且只建立唯一的一個

JavaScript中的單例:全域性變數當成單例來使用,缺點:名稱空間汙染

(2)策略模式

定義:將一個個演算法(解決方案)封裝在一個個策略類中,並且使他們可以相互替換

特點:一個基於策略模式的演算法至少由兩部分組成,一部分是策略類,封裝了具體演算法負責計算過程,另一部分是環境類,接受客戶請求,將請求託付給某一個策略類

優點:

  • 策略模式可以避免程式碼中的多重判斷條件。

  • 策略模式很好的體現了開放-封閉原則,將一個個演算法(解決方案)封裝在一個個策略類中。便於切換,理解,擴充套件。

  • 策略中的各種演算法可以重複利用在系統的各個地方,避免複製貼上。

  • 策略模式在程式中或多或少的增加了策略類。但比堆砌在業務邏輯中要清晰明瞭。

  • 違反最少知識原則,必須要了解各種策略類,才能更好的在業務中應用。

    應用場景:根據不同的員工績效計算不同的獎金;表單驗證中的多種校驗規則。

(3)代理模式

定義:為一個物件提供一個代用品或佔位符,以便控制對它的訪問。

應用場景:圖片懶載入(先通過一張loading圖佔位,然後通過非同步的方式載入圖片,等圖片載入好了再把完成的圖片載入到img標籤裡面。)

(4)迭代器模式

//TODO

(5)釋出/訂閱模式

定義:又叫觀察者模式,它定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都將得到通知。

場景:訂閱感興趣的專欄和公眾號。

實現方法:

  • 先指定好釋出者

  • 給釋出者加一個快取列表,用於儲存回撥函式通知訂閱者

  • 釋出訊息時,遍歷快取列表,觸發存放的訂閱者回調函式

    簡單版程式碼實現:

     1 let event = {
     2   clientList: [],
     3   listen: function(key, fn) {
     4     if (!this.clientList[key]) {
     5       //  如果沒有訂閱過此類訊息,則給該類訊息建立一個快取列表
     6       this.clientList[key] = []
     7     }
     8     this.clientList[key].push(fn)
     9   },
    10   trigger: function() {
    11     // 取第一個引數,即key值
    12     const key = Array.prototype.shift.call(arguments)
    13     const fns = this.clientList[key]
    14     //  如果沒有訂閱該訊息則返回
    15     if (!fns || fns.length === 0) {
    16       return false
    17     }
    18     //  遍歷列表
    19     for (var i = 0, fn; (fn = fns[i]); i++) {
    20       fn.apply(this, arguments)
    21     }
    22   },
    23   remove: function(key, fn) {
    24     //  取消訂閱
    25     let fns = this.clientList[key]
    26     if (!fns) {
    27       return flase
    28     }
    29     if (!fn) {
    30       // 如果key對應的訊息沒人訂閱則直接返回
    31       fns && (fns.length = 0)
    32     } else {
    33       for (let l = fns.length - 1; l >= 0; l--) {
    34         let _fn = fns[l]
    35         if (_fn === fn) {
    36           fns.splice(l, 1)
    37         }
    38       }
    39     }
    40   },
    41 }
    42 ​
    43 let salesOffices = {}
    44 installEvent(salesOffices)
    45 salesOffices.listen('123', fn1 = function(squareMeter)  {
    46   console.log('面積為1:', squareMeter)
    47 })
    48 salesOffices.listen('123', fn2 = function(squareMeter) {
    49   console.log('面積為2:', squareMeter)
    50 })
    51 salesOffices.trigger('123', fn1)
    52 salesOffices.remove('123',fn1)
    53 salesOffices.trigger('123', fn1)
    54  
    55 
    56  

     

(6)中介者模式

定義:通過一箇中介者物件,其他所有相關物件都通過該中介者物件來通訊,而不是互相引用,當其中的一個物件發生改變時,只要通知中介者物件就可以。可以解除物件與物件之間的緊耦合關係。

應用場景: 例如購物車需求,存在商品選擇表單、顏色選擇表單、購買數量表單等等,都會觸發change事件,那麼可以通過中介者來轉發處理這些事件,實現各個事件間的解耦,僅僅維護中介者物件即可。

(7)裝飾者模式

定義:在不改變物件自身的基礎上,在程式執行期間給物件動態的新增方法。

應用場景: 有方法維持不變,在原有方法上再掛載其他方法來滿足現有需求;函式的解耦,將函式拆分成多個可複用的函式,再將拆分出來的函式掛載到某個函式上,實現相同的效果但增強了複用性。

參考書籍:JavaScript設計模式與開發實踐 曾探