[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';
}
```
创建实例对象的职责和管理单例的职责分别放置在两个方法里,这两个方法可以独立变化而互不影响。