banner
无关风月

无关风月

当我与世界初相见
email
douban
bilibili

JavaScript設計模式

探討一些經典和現代的設計模式的 JavaScript 實現。

沒有最好的,只有最合適的

設計模式一共分為 3 大類 23 種

模式類型設計模式
創建型模式單例模式、工廠模式、建造者模式
結構型模式適配器模式、裝飾器模式、代理模式
行為型模式策略模式、觀察者模式、發布訂閱模式、職責鏈模式、中介者模式

單例模式#

一個類只有一個實例,並提供一個訪問他的全局訪問點

image-20230319225821142

  • Singleton :特定類,這是我們需要訪問的類,訪問者要拿到的是它的實例;

  • instance :單例,是特定類的實例,特定類一般會提供 getInstance 方法來獲取該單例;

  • getInstance :獲取單例的方法;

class Singleton {
    let _instance = null;
    static getInstance() {
        if (!Singleton._instance) {
          Singleton.instance = new Singleton()
        }
        // 如果這個唯一的實例已經存在,則直接返回
        return Singleton._instance
    }
}

const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()

console.log(s1 === s2)  // true

實例#

Vuex 實現了一個全局的 store 用來存儲應用的所有狀態。這個 store 的實現就是單例模式的典型應用。

使用場景#

  1. 如果一個類實例化過程消耗資源比較多,可以使用單例避免性能浪費

  2. 需要公共狀態,可以使用單例保證訪問一致性。

工廠模式#

工廠模式:根據不同的參數,返回不同類的實例。將對象的創建與對象的實現分離。實現複雜,但使用簡單。直接使用工廠提供的方法即可

優點:

  1. 良好的封裝,訪問者無需了解創建過程,代碼結構清晰。

  2. 擴展性良好,通過工廠方法隔離了用戶和創建流程,符合開閉原則。

缺點:

給系統增加了抽象性,帶來了額外的系統複雜度,不能濫用

實例#

document.createElement 創建 DOM 元素。這個方法採用的就是工廠模式,方法內部很複雜,但外部使用很簡單。

使用場景#

  • 對象創建比較複雜,訪問者無需了解創建過程。

  • 需要處理大量具有相同 / 類似屬性的小對象。

適配器模式#

用於解決兼容問題,接口 / 方法 / 數據不兼容,將其轉換成訪問者期望的格式進行使用。

image-20230319230730502

場景特點:

  1. 整合第三方 SDK
  2. 封裝舊接口

裝飾器模式#

  • 動態地給某個對象添加一些額外的職責,是一種實現繼承的替代方案
  • 在不改變原對象的基礎上,通過對其進行包裝擴展,使原有對象可以滿足用戶的更複雜需求,而不會影響從這個類中派生的其他對象

image-20230319230958645

有點原型鏈的味道

代理模式#

為一個對象提供一個代用品或佔位符,以便控制對它的訪問

使用場景#

  • ES6 的 proxy
  • jQuery.proxy () 方法

裝飾者與代理模式的區別#

  • 裝飾者模式: 擴展功能,原有功能不變且可直接使用
  • 代理模式: 顯示原有功能,但是經過限制之後的

策略模式#

定義一系列算法,根據輸入的參數決定使用哪個算法。

image-20230319231627454

實例#

場景:雙十一滿減活動。滿 200-20、滿 300-50、滿 500-100。這個需求,怎麼寫?

// if-else:臃腫,難改動
function priceCalculate(discountType,price){
    if(discountType === 'discount200-20'){
        return price - Math.floor(price/200) * 20;
    }else if(discountType === 'discount300-50'){
        return price - Math.floor(price/300) * 50;
    }else if(userType === 'discount500-100'){
        return price - Math.floor(price/500) * 100;
    }
}
//策略模式改寫,隱藏了算法,預留了增加策略的入口,便於拓展

const priceCalculate = (function(){
    const discountMap = {
        'discount200-20': function(price) {
            return price - Math.floor(price / 200) * 20;
        },
        'discount300-50': function(price) {
            return price - Math.floor(price/300) * 50;
        },
        'discount500-100': function(price) {
            return price - Math.floor(price/500) * 100;
        },
    };
    return {
        addStategy(stategyName,fn){
            if(discountMap[stategyName]) return;
            discountMap[stategyName] = fn;
        },
        priceCal(discountType,price){
            return discountMap[discountType] && discountMap[discountType](price);
        }
    }
})()

優點:

  1. 策略相互獨立,可以互相切換。提高了靈活性以及復用性。
  2. 不需要使用if-else進行策略選擇,提高了維護性。
  3. 可擴展性好,滿足開閉原則。

缺點:

  1. 策略相互獨立,一些複雜的算法邏輯無法共享,造成資源浪費。
  2. 用戶在使用策略時,需要了解具體的策略實現。不滿足最少知識原則,增加了使用成本。

使用場景#

  1. 算法需要自由切換的場景。
  2. 多個算法只有行為上有些不同,可以考慮策略模式動態選擇算法。
  3. 需要多重判斷,可以考慮策略模式規避多重條件判斷。

觀察者模式#

一個對象(稱為 subject)維持一系列依賴於它的對象(稱為 observer),將有關狀態的任何變更自動通知給它們(觀察者)。

優缺點#

優點:目標變化就會通知觀察者,這是觀察者模式最大的優點。

缺點: 目標和觀察者是耦合在一起的,要實現觀察者模式,必須同時引入被觀察者和觀察者才能達到響應式的效果。

使用場景#

假設 B 站用戶就是觀察者,B 站 up 主是被觀察者,有多個的 B 站用戶關注了青春湖北這個 up 主,當這個 up 主更新視頻時就會通知這些關注的 B 站用戶。

發布訂閱模式#

基於一個主題,希望接收通知的對象(稱為 subscriber)通過自定義事件訂閱主題,被激活事件的對象(稱為 publisher)通過發布主題事件的方式被通知。

使用場景#

微信會關注很多公眾號,公眾號有新文章發布時,就會有消息及時通知我們文章更新了。

這個時候公眾號為發布者,用戶為訂閱者,用戶將訂閱公眾號的事件註冊到事件調度中心,當發布者發布新文章時,會發布事件至事件調度中心,調度中心會發消息告訴訂閱者。

Vue 雙向綁定中的發布訂閱模式#

image-20230319232727395

Vue 雙向綁定通過數據劫持和發布 - 訂閱模式實現

  • 通過DefineProperty劫持各個數據的settergetter,並為每個數據添加一個訂閱者列表,這個列表將會記錄所有依賴這個數據的組件。

    響應式數據相當於消息的發布者。

  • 每個組件都對應一個Watcher訂閱者,當組件渲染函數執行時,會將本組件的Watcher加入到所依賴的響應式數據的訂閱者列表中。

    這個過程叫做 “依賴收集”。

  • 當響應式數據發生變化時,會出settersetter負責通知數據的訂閱者列表中的WatcherWatcher觸發組件重新渲染來更新視圖。

    視圖層相當於消息的訂閱者。

觀察者模式和發布訂閱的區別#

觀察者是經典軟件設計模式中的一種,但發布訂閱只是軟件架構中的一種消息範式

觀察者模式發布訂閱
2 個角色3 個角色
重點是被觀察者重點是發布訂閱中心

觀察與被觀察的關係是通過被觀察者主動建立的,被觀察者至少要有三個方法 —— 添加觀察者、移除觀察者、通知觀察者。

發布訂閱基於一個中心來建立整個體系,其中發布者訂閱者不直接進行通信,而是發布者將要發布的消息交由中心管理,訂閱者也是根據自己的情況,按需訂閱中心中的消息。

發布訂閱的實現內部利用了觀察者模式,但由於發布訂閱中心這一中間層的出現,對於生產方和消費方的通信管理變得更加的可管理和可拓展。

理解【觀察者模式】和【發布訂閱】的區別 - 掘金 (juejin.cn)

JS 常用的六種設計模式介紹 - 掘金 (juejin.cn)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。