[TOC]
# 單例模式
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點
## 簡單的單例模式
```javascript
var Singleton = function(name){
this.name = name;
this.instance = null;
}
Singleton.prototype.getName = function(){
return this.name;
}
Singleton.getInstance = function(name){
if(!this.instance){
this.instance = new Singeton(name);
}
return this.instance;
}
var a = Singleton.getInstance('1');
var b = Singleton.getInstance('2');
alert(a === b) // true
// or
var Singleton = function(name){
this.name = name;
}
Singleton.prototype.getName = function(){
return this.name;
}
Singleton.getInstance = (function(){
var instance;
return function(name){
if(!instance){
instance = new Singleton(name);
}
return instance;
}
})();
```
通過`Singleton.getInstance`獲取了`Singleton`的唯一對象,但是這么做,意義并不大。
## 透明的單例模式
從這個類中創建對象時,用戶可以像使用普通的一個類一樣進行使用,其實就是不需要向上面一樣,通過`Singleton.getInstance`進調用
```javascript
var CreateDiv = (function(){
var instance;
var CreateDiv = function(html){
if(instance){
return instance
}
this.html = html;
this.init();
return instance = this;
}
CreateDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}
return CreateDiv;
})();
var a = new CreateDiv('1');
var b = new CreateDiv('2');
// a === b =>true
```
## 用代理實現單例模式
```javascript
var CreateDiv = function(html){
this.html = html;
this.init();
};
CreateDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}
var ProxySingletonCreateDiv = (function(){
var instance;
return function(html){
if(!instance){
instance = new CreateDiv(html);
}
return instance;
}
})();
var a = ProxySingletonCreateDiv('1');
var b = ProxySingletonCreateDiv('2');
// a === b => true
```
將`CreateDiv`剝離出來為單獨的一個類,通過代理的方式去創建`CreateDiv`,兩者結合就成為了單例模式,即`CreateDiv`負責正常的業務邏輯,`ProxySingleCreateDiv`負責創建單例
## 惰性單例
在需要的時候才創建對象實例
```javascript
var createLoginLayer = (function(){
var div;
return function(){
if(!div){
div = document.createElement('div');
div.innerText = '這是彈窗';
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
})();
document.getElementById('loginBtn').onclick = function(){
var layer = createLoginLayer();
layer.style.display = 'block';
}
```
## 通用的惰性單例
邏輯都是一致的,用一個變量來標志是否創建一個對象,是則返回。
```javascript
var obj;
if(!obj){
obj = xxx
}
return obj;
```
則對代碼進行剝離,將創建單例的代碼取出,業務代碼也剝離出來;
```javascript
var getSingleton = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
}
var createLoginLayer = function(){
var div;
return function(){
if(!div){
div = document.createElement('div');
div.innerText = '這是彈窗';
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
});
var singletonCreateLoginLayer = getSingleton(createLoginLayer);
document.getElementById('loginBtn').onclick = function(){
var layer = singletonCreateLoginLayer();
layer.style.display = 'block';
}
```
創建實例對象的職責和管理單例的職責分別放置在兩個方法里,這兩個方法可以獨立變化而互不影響。