通用惰性單例模式

本文不單單是對於單例模式的總結,在最後還有對通用惰性單例的探討和完善,不想看單例模式基礎總結的能夠直接跳轉到「通用的單例中間類」來看我對於網絡上流傳的通用惰性單例模式的想法javascript

單例模式

實現思路

用一個變量來標記當前的類是否建立過對象,若是沒建立過,返回建立以後的實例,若是以前已經建立過,則返回以前建立過的實例java

單例模式「不透明」

// 構造函數
function Singleton(name) {
    this.name = name
    this.instance = null
}
// 構造函數方法
Singleton.prototype.getName = () => {
    console.info(this.name)
}
// 單例控制
Singleton.getInstance = (name) => {
    if(!this.instance) {
        this.instance = new Singleton(name)
    }
    return this.instance
}

const a = Singleton.getInstance('a')
const b = Singleton.getInstance('b')

console.info(a, b) // true
複製代碼

也可使用閉包segmentfault

// 構造函數
function Singleton(name) {
    this.name = name
}
// 構造函數方法
Singleton.prototype.getName = function() {
    console.info(this.name)
}
// 獲取類的實例
Singleton.getInstance = (function() {
    let instance = null
    return function(name) {
        if(!instance) {
            instance = new Singleton(name)
        }
        return instance
    }        
})()

// 獲取對象1
var a = Singleton.getInstance('a')
// 獲取對象2
var b = Singleton.getInstance('b')
// 進行比較
console.info(a, b)
複製代碼

固然也可使用 ES6 的 class網絡

class Singleton {
    constructor(name) {
        this.name = name
    }

    getName() {
        console.info(this.name)
    }

    getInstance = (function(){
        let instance = null
        return function(name) {
            if(!instance) {
                instance = new Singleton(name)
            }
            return instance
        }   
    })()
}

// 獲取對象1
var a = Singleton.getInstance('a')
// 獲取對象2
var b = Singleton.getInstance('b')
// 進行比較
console.info(a, b)
複製代碼

可是此方法必需要使用 Singleton.getInstance() 才能獲取到想要的實例,這與咱們習覺得常的 new 關鍵字獲取實例對象有很大區別。其實這種方法的實現思路就是用構造函數中的一個方法去控制此構造函數生成的實例爲單例,既然咱們想要用 new關鍵字來生成單例,那咱們爲什麼不用另外一個構造函數來控制此構造函數的建立呢閉包

單例模式「透明」

class Person {
    constructor(name) {
        this.name = name
    }
    getName() {
        return this.name
    }
}

const Singleton = (function() {
    let instance
    return function(name) {
        if(!instance) {
            instance = new Person(name)
        }
        return instance
    }
})()


// 獲取對象1
let a = new Singleton('a')
let b = new Singleton('b')
console.info(a === b) // true

複製代碼

以上中間控制方法或類中的構造函數都是固定的,也就是說咱們須要爲不一樣的構造函數編寫不一樣的中間方法或類,這樣顯然是不合理的。app

通用的單例中間類

我發現如今流傳在網上的基本上是以下這種函數

// 獲取單獨的實例
var singleton = function(fn) {
    var instance;
    return function() {
        return instance || (instance = fn.apply(this, arguments));
    }
}

// 建立遮罩層
var createMask = function(){
    // 建立div元素
    var mask = document.createElement('div');
    // 設置樣式
    mask.style.position = 'fixed';
    mask.style.top = '0';
    mask.style.right = '0';
    mask.style.bottom = '0';
    mask.style.left = '0';
    mask.style.opacity = 'o.75';
    mask.style.backgroundColor = '#000';
    mask.style.display = 'none';
    mask.style.zIndex = '98';
    document.body.appendChild(mask);
    // 單擊隱藏遮罩層
    mask.onclick = function(){
        this.style.display = 'none';
    }
    return mask;
};

// 調用
var oMask = singleton(createMask)()
var eMask = singleton(createMask)()
// 可是 oMask 與 eMask 不相等,獲取 eMask 時其實也建立了新的 div
複製代碼

這種調用方法其實僅僅是獲取到了 createMask 中的返回值,每次 singleton() 其實都會執行 var instance ,因此對 instance 的判斷實際上是沒用的。正確調用我以爲應該以下ui

const maskSingleton = singleton(createMask) // 先用一個變量接一下
const oMask = maskSingleton()
const eMask = maskSingleton() // 此時返回的仍是以前已經建立的 mask
複製代碼

但其實上面的例子並未很好的體現出通用惰性單例模式的做用,並且oMask 實際上是獲取不到 createMask 原型鏈上的方法的「也可能本來做者就不想獲取 = =」,但咱們以前的舉例都是使用構造函數的舉例,因此接下來我也會用構造函數的例子來展示。this

const singleton = function(Fn) {
    var instance
    return function() {
        return instance || (instance = new Fn(...arguments))
    }
}

const Person = function(name){
    this.name = name
}

Person.prototype.getName = function() {
    return this.name
}

const Animal = function(name) {
    this.name = name
}

Animal.prototype.getName = function() {
    return this.name
}

const PersonSingleton = singleton(Person)
const liSi = PersonSingleton('liSi')
const zhangSan = PersonSingleton('zhangSan')

const AnimalSingleton = singleton(Animal)
const cat = AnimalSingleton('cat')
const dog = AnimalSingleton('dog')

console.info(zhangSan.getName()) // 'liSi'
console.info(dog.getName()) // 'cat'
複製代碼

參考連接: segmentfault.com/a/119000001…spa

相關文章
相關標籤/搜索