說說你對單例模式的理解?如何實現?

林恒發表於2024-05-31

一、是什麼

單例模式(Singleton Pattern):建立型模式,提供了一種建立物件的最佳方式,這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立

在應用程式執行期間,單例模式只會在全域性作用域下建立一次例項物件,讓所有需要呼叫的地方都共享這一單例物件,如下圖所示:

從定義上來看,全域性變數好像就是單例模式,但是一般情況我們不認為全域性變數是一個單例模式,原因是:

  • 全域性命名汙染
  • 不易維護,容易被重寫覆蓋

二、實現

javascript中,實現一個單例模式可以用一個變數來標誌當前的類已經建立過物件,如果下次獲取當前類的例項時,直接返回之前建立的物件即可,如下:

// 定義一個類
function Singleton(name) {
    this.name = name;
    this.instance = null;
}
// 原型擴充套件類的一個方法getName()
Singleton.prototype.getName = function() {
    console.log(this.name)
};
// 獲取類的例項
Singleton.getInstance = function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance
};

// 獲取物件1
const a = Singleton.getInstance('a');
// 獲取物件2
const b = Singleton.getInstance('b');
// 進行比較
console.log(a === b);

使用閉包也能夠實現,如下:

function Singleton(name) {
    this.name = name;
}
// 原型擴充套件類的一個方法getName()
Singleton.prototype.getName = function() {
    console.log(this.name)
};
// 獲取類的例項
Singleton.getInstance = (function() {
    var instance = null;
    return function(name) {
        if(!this.instance) {
            this.instance = new Singleton(name);
        }
        return this.instance
    }        
})();

// 獲取物件1
const a = Singleton.getInstance('a');
// 獲取物件2
const b = Singleton.getInstance('b');
// 進行比較
console.log(a === b);

也可以將上述的方法稍作修改,變成建構函式的形式,如下:

// 單例建構函式
function CreateSingleton (name) {
    this.name = name;
    this.getName();
};

// 獲取例項的名字
CreateSingleton.prototype.getName = function() {
    console.log(this.name)
};
// 單例物件
const Singleton = (function(){
    var instance;
    return function (name) {
        if(!instance) {
            instance = new CreateSingleton(name);
        }
        return instance;
    }
})();

// 建立例項物件1
const a = new Singleton('a');
// 建立例項物件2
const b = new Singleton('b');

console.log(a===b); // true

三、使用場景

在前端中,很多情況都是用到單例模式,例如頁面存在一個模態框的時候,只有使用者點選的時候才會建立,而不是載入完成之後再建立彈窗和隱藏,並且保證彈窗全域性只有一個

可以先建立一個通常的獲取物件的方法,如下:

const getSingle = function( fn ){
  let result;
  return function(){
    return result || ( result = fn .apply(this, arguments ) );
  }
}; 

建立彈窗的程式碼如下:

const createLoginLayer = function(){
  var div = document.createElement( 'div' );
  div.innerHTML = '我是浮窗';
  div.style.display = 'none';
  document.body.appendChild( div );
  return div;
}; 

const createSingleLoginLayer = getSingle( createLoginLayer ); 

document.getElementById( 'loginBtn' ).onclick = function(){
  var loginLayer = createSingleLoginLayer();
  loginLayer.style.display = 'block';
};

上述這種實現稱為惰性單例,意圖解決需要時才建立類例項物件

並且Vuexredux全域性態管理庫也應用單例模式的思想,如下圖:

現在很多第三方庫都是單例模式,多次引用只會使用同一個物件,如jquerylodashmoment...

參考文獻

  • https://zh.wikipedia.org/zh-hans/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F
  • https://www.runoob.com/design-pattern/singleton-pattern.html
  • https://juejin.cn/post/6844903874210299912#heading-5

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。

說說你對單例模式的理解?如何實現?

相關文章