單例模式定義:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
單例模式場景:有一些對象往往只需要有一個,比如線程池、全局緩存瀏覽器中的Windows對象等
1、實現單例模式
要實現一個標準的單例模式並不複雜,無非是用一個變量來標誌當前是否已經爲某個類創建過對象,如果是則在下一次獲取該類的實例時,直接返回之前創建的對象
或者:
var Singleton = function(name) {
this.name = name;
}
Singleton.prototype.getName = function() {
console.log(this.name)
}
Singleton.getInstance = (function(name) {
var instance = null
return function(name) {
if(!instance) {
instance = new Singleton(name)
}
return instance
}
})()
var a = Singleton.getInstance('aa')
var b = Singleton.getInstance('bb')
console.log(a === b) // true
但是這種方法增加了類的“不透明性”,Singleton必須知道這是一個單例類,且getInstance方法是不透明的,使用必須知道又該方法,當我們打印console.log(new Singleton('cc')),結果如下:
2、透明的單例模式
目的:創建該類時候,可以像使用其他普通類一樣;
例子:我們將創建一個CreateDiv單例類,它的作用是在頁面中創建唯一的div節點
這裏可以看到當我們console.log(b)時,構造函數html的值還是'marin',到這裏我要明確一點 單例模式定義:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
但是它還是有一些缺點。未了把判斷的標誌變量instance封裝起來,我們使用了匿名函數(自運行)和閉包,並讓讓這個匿名函數返回真正的Singleton構造方法,這讓閱讀起來很難理解,同時增加了程序的複雜程度
var CreateDiv = function(html) {
if(instance) {
return instance
}
this.html = html;
this.init();
return instance = this
}
這段代碼中 CreateDiv的構造函數實際負責兩件事,1、創建實例對象(instance=this)並保證只用一個實例if(instance)。2、執行初始化init()。這裏還有個缺點(函數的單一職責原則)
假如我們某一天需要用這個類,在頁面創建多個div,即要讓這個類從單例類變成一個普通的可以生產多個實例的類,那我們就必須改寫CreateDiv構造函數,把控制創建唯一的標誌變量 var instance去掉,這種修改會帶來不必要的煩惱。
3、用代理來實現單例模式
這樣一來就將 CreateDiv變成一普通類,僅僅去創建div,
實現單例模式讓ProxySingleton 去實現
單例模式的核心是確保只有一個實例,並提供全局訪問