定义:单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象等。当我们创建的对象只会被创建一次时,这个时候就适合用单例模式来创建,因为当我们点击登录按钮的时候,页面会出现一个悬浮窗,而这个悬浮窗是唯一的,无论单击多少次登录按钮,这个只会被创建一次。
实现单例模式
实现一个标准的单例模式,用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。代码如下:
var Singleton = function( name ){
this.name = name;
this.instance = null;
};
Singleton.prototype.getName = function(){
alert( this.name );
};
Singleton.getIstance = function( name ){
if( !instance ){
this.instance = new Singleton( name );
}
return this.instance;
};
var a = Singleton.getInstance( 'tom' );
var b = Singleton.getInstance( 'sun' );
alert( a===b ); //true
我们通过Singleton.getInstance来获取Singleton类的唯一对象,简单,但有一个问题,就是增加了这个类的“不透明性”,Singleton类的使用者必须知道这是一个单例类,跟以往通过new XXX的方式来获取对象不同,这里偏要使用Singleton.getInstance来获取对象。
透明的单例模式
实现一个“透明”的单例类,可以是用户从这个类中创建对象的时候,可以像使用其他普通函数一样。
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('tom');
var b = new createDiv('sun');
alert( a === b ); //true
createDiv的构造函数实际上负责了两件事情。第一是创建对象和执行初始化init方法,第二个是保证只有一个对象。有一个缺点,假如我们某天需要利用这个类,在页面中创建千千万万个div,即要这个类从单例类变成一个普通的可产生多个实例的类,那我们就要改写createDiv构造函数,把控制创建唯一对象的那一段去掉,这样会给我们带来不必要的麻烦。
代理类实现单例模式
我们现在通过代理类来解决透明单例模式提到的问题。
通过引入代理类的方式,把负责管理单例的逻辑移到了代理类proxySingDivCreateDiv中,这样,createDiv就变成了一个普通类,它跟代理类组合起来可以实现单例模式的效果。
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 = new proxySingletonCreateDiv( 'tom' );
var b = new proxySingletonCreateDiv( 'sun' );
alert( a === b ); //true