JavaScript設計模式(一):單例模式

圖片描述

單例模式:限制類實例化次數只能一次,一個類只有一個實例,並提供全局訪問點。(歸屬創建型設計模式)

模式特點

  1. 類只有一個實例
  2. 全局可訪問該實例
  3. 自行實例化(主動實例化)
  4. 可推遲初始化,即延遲執行(與靜態類/對象的區別)

實現方式

實現方式:使用一個變量存儲類實例對象(值初始爲 null/undefined )。進行類實例化時,判斷類實例對象是否存在,存在則返回該實例,不存在則創建類實例後返回。多次調用類生成實例方法,返回的同一個實例對象。

代碼實現

class Singleton {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}
Singleton.getInstance = (function () {
  let instance;
  return function (name) {
    if (!instance) {
      instance = new Singleton(name);
    }
    return instance;
  }
})();

var Winner = Singleton.getInstance('Winner');
var Looser = Singleton.getInstance('Looser');

console.log(Winner === Looser); // true
console.log(Winner.getName());  // 'Wiinner'
console.log(Looser.getName());  // 'Looser'

代碼中定義了一個 Singleton 類,並定義 Singleton.getInstance() 方法來生成實例對象。而不是通過 new 操作符來創建類實例。

Singleton.getInstance() 中,通過閉包引用存儲類實例的對象,判斷類是否實例化過。(這裏閉包的使用能夠使 getInstance() 多次調用都能獲取到之前類實例的存儲值)。因此無論執行多少次 Singleton.getInstance() 方法,都只會返回同一個Singleton類實例對象。

使用場景

“單例模式的特點,意圖解決:維護一個全局實例對象。”

  1. 引用第三方庫
  2. 彈窗登錄框
  3. 購物車
  4. 全局態管理 store (Vuex / Redux)

項目中引入第三方庫時,重複加載庫文件,全局只會實例化一個庫對象,如 jQuerylodashmoment ..., 其實它們的實現方式也是單例模式應用的一種:

// 引入代碼庫 libs(庫別名)
if (window.libs != null) {
  return window.libs;    // 直接返回
} else {
  window.libs = '...';   // 初始化
}

單例設計模式實現全局彈窗登錄框:

class LoginModal {
    constructor() {
        const div = document.createElement('div');
        div.innerHTML = '登錄框HTML內容';
        div.style.display = 'none';
        this.el = div;
        this.visible = false;
        document.body.append(div);
        return div;
    }
    show() {
        this.el.style.display = 'block';
    }
    hide() {
        this.el.style.display = 'none';
    }
    toggle() {
        this.visible = !this.visible;
        this.visible ? this.show() : this.hide();
    }
}

LoginModal.getInstance = (function() {
    let instance;
    return function() {
        if (!instance) {
            instance = new LoginModal();
        }
        return instance;
    }
})();

// 按鈕切換顯示登錄框
document.getElementById('btn-login').addEventListener('click', function(){
    LoginModal.getInstance().toggle();
})

優缺點

  • 優點:適用單一對象,只生成一個對象實例,減少內存開銷,避免頻繁創建和銷燬實例。
  • 缺點:不適用動態擴展對象,如通過對象繼承擴展新對象。

TIPS: 多線程編程語言中,單例模式會涉及同步鎖的問題。而JavaScript是單線程的編程語言,可忽略該問題。


參考文章

本文首發Github,期待Star!
https://github.com/ZengLingYong/blog

作者:以樂之名
本文原創,有不當的地方歡迎指出。轉載請指明出處。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章