js設計模式之單例模式


1、定義

保證一個類僅生成一個實例,並可以全局訪問。

2、應用范圍

單列模式應用非常廣泛,有些場景下某些對象只需要一個,比如瀏覽器中的window對象,全局緩存對象等。在實際開發過程中應用也比較多,比如點擊一個按鈕產生一個登陸框,無論點擊多少次都應該只在第一次產生這個登錄框,而在后面點擊N次也只能是復用這個登陸框,而非重新創建,這樣的場景就可以使用單列模式來創建這個登陸框。

3、實現一個簡單的單例模式

//簡單版單列模式
const Singleton = function (name) {
    this.name = name
    //這個instance來保存生成的實例
    this.instance = null
}
Singleton.prototype.getName = function () {
    return this.name
}

//靜態方法
Singleton.getInstance = function (name) {
    if (!this.instance){
        this.instance = new Singleton(name)
    }
    return this.instance
    
}

const A = Singleton.getInstance('A') 
const B = Singleton.getInstance('B')
console.log(A === B); //true
console.log(A.getName()); //A
console.log(B.getName()); //A

要實現起來並不復雜,無非就是使用一個私有變量去保存已生成的實例,在下新建時判斷是否存在這個實例,若存在直接返回,而不創建就OK了。

4、透明版

透明板也就要用new Constructor的形式創建對象,使用單例的類就像使用普通的類一樣。
下面我們使用閉包的形式來寫一個單列類,並使用閉包的局部變量來保存已生成的實例。

//透明板單列模式

const Singleton = (function () {
    let instance = null
    //實現一個簡單的類
    function createDiv(html){
        if (instance){
            return instance
        }
        this.html = html

        return instance = this
    }
    createDiv.prototype.init = function () {
        let div = document.createElement('div')
        div.innerHTML = this.html
        document.body.append(div)
    }

    return createDiv
})()
const A = new Singleton('A') 
const B = new Singleton('B')
console.log(A === B); //true

5、代理版

代理版本要實現的目標是將定義類的代碼和管理單例的代碼分開,實現更小粒度的划分,遵循單一職責原則

const Singleton = function (name){
    this.name = name
}
const proxySingleton = (function () {
    let instance = null
    return function (name) {
        if (!instance){
            instance = new Singleton(name)
        }
        return instance
    }
})()

6、惰性單例

前面寫的例子都是基於'類'的單例模式,其目的在與創建一個唯一的由'類'生成的對象(這里的'類'指的是偽類,也就是我們把javascript中的構造函數當做其他傳統語言中的類來進行理解,而其實javascript中是不存在類的的概念,所有對象都是構造函數基於原型克隆出來的,快扯到面向對象去了,這里就不多說了)
理解惰性單例有如下兩點
1、而現在要理解的 "惰性單例"的概念,我們的思想不再局限於去實現一個全局唯一的由偽類生成的對象,我們維持的唯一單例可能是一個div,可能是一個列表,也自然可能是一個對象。
2、另外要理解的是 '惰性'二字,也即 我們維持的單例在不需要的情況下是不會產生的,只有在需要的情況才會生成,其實這一點在第二節簡單的單例模式里面就已經實現了,只有調用Singleton.getInstance才會生成,並且生成后會一直存在,等待復用
一個例子:
比如我們需要一個登陸框,而在頁面上點擊登陸就會彈出這個登陸框,無論多次點擊生成的都應該是同一個DOM節點,而這個DOM節點只在第一次調用生成,后面點擊登陸只會復用這個DOM節點。這里我們維持的唯一單例應該是登陸框的DOM節點,並且是惰性生成的,即永不點擊登錄,就永遠不會生成該DOM節點。
下面給出惰性單例的通用代碼

//惰性單例通用代碼
const getSingle = function (fn){
    let instance = null;
    return function (){
        return instance || (instance = fn.call(this, arguments))
    }
}

要實現上面維持登錄框單例的例子, 這里說一下思路, fn的功能是產生登錄框,並返回登錄框的DOM,代碼如下

const createLoginLayer = function(){
    let div = document.createElement( 'div' );
    div.innerHTML = '我是登錄浮窗';
    div.style.display = 'none';
    document.body.appendChild( div );
    return div;
};
let createSingleLoginLayer = getSingle( createLoginLayer );
document.getElementById( 'loginBtn' ).onclick = function(){
    let loginLayer = createSingleLoginLayer();
    loginLayer.style.display = 'block';
};

7、小結

單例模式在開發過程中應用很廣泛,特別是惰性單例,所以也是我們必須要掌握的點。然后要再啰嗦幾句的就是關於,單一職責原則,開放封閉原則,最少知識原則等等面向對象的概念,無論是上面提到的還是沒提到的,我們都需要有一定的了解,熟悉這些原則並應用於實際對於代碼質量的提升肯定是巨大的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM