单例形式被熟知是由于它把一个类的实例化限定在只要一个对象。传统的完成体式格局是:建立一个类,这个类内里有一个要领在对象不存在的时刻制造一个实例,存在的时刻,只须要返回这个对象的援用即可。
单例和静态类(或许对象)是有区分的,由于我们可以耽误他们的初始化。由于他们须要一些在初始化的时刻不能取得的信息。他们没有供应一种体式格局让不晓得他们之前援用的代码去猎取他们。这是由于由单例返回的既不是对象也不是类,而是一种组织。想一想大括号构成的不是真正的闭包,函数作用于供应的闭包才是真正的闭包。
Javascript中,单例作为共享资本的定名空间,它隔离了完成的代码和全局变量,为了可以让函数有唯一的一个进口。
我们可以经由过程下面的要领完成单例:
var mySingleton=(function(){
//存储单例援用的实例
var instance;
function init(){
//单例
//私有要领和属性
function privateMethod(){
console.log("I am private");
}
var privateVariable="Im alse private";
var privateRandomNumber=Math.random();
return {
//公有要领和属性
publicMethod:function(){
console.log("The public can see me!");
},
publicProperty:"I am also public",
getRandomNumber:function(){
return privateRandomNumber;
}
};
}
return {
//假如存在猎取单例实例的援用
//不存在,建立实例
getInstance:function(){
if(!instance){
instance=init();
}
return instance;
}
};
})();
var myBadSingleton=(function(){
//指向单例的援用
var instance;
function init(){
//单例
var privateRandomNumber=Math.random();
return {
getRandomNumber:function(){
return privateRandomNumber;
}
}
}
return {
//不管什么时刻都建立一个单例实例
getInstance:function(){
instance=init();
return instance;
}
};
})();
//运用:
var singleA=mySingleton.getInstance();
var singleB=mySingleton.getInstance();
console.log(singA.getRandomNumber()===singleB.getRandomNumber()); //true
var badSingleA=myBadSingleton.getInstance();
var badSingleB=myBadSingleton.getInstance();
console.log(badSingleA.getRandomNumber()!==badSingleB.getRandomNumber());//true
//注重:由于我们运用的是随机数
//所以上面的值照样有能够雷同的
//然则能够性很低,上面的例子照样有效的。
运用单例可以让我们有一个指向实例的一致进口(平常经由过程MySingleton.getInstance()
的体式格局),如许我们就不须要直接经由过程new MySingleton()
的体式格局直接挪用啦。这在javascript中也是可以完成的。
在四人帮这本书中,单例的实用场景被形貌为下面这些:
必需只要一个类的实例,而且必需可以经由过程人人都晓得的进口让人人可以接见到。
当这个唯一的实例须要被之类扩大的时刻,用户可以在不须要修正代码的情况下扩大它。
第二点指出了我们能够碰到的场景,比方:
mySingleton.getInstance=function(){
if(this._instance==null){
if(isFoo()){
this._instance=new FooSingleton();
}else{
this._instance=new BasicSingleton();
}
}
return this._instance;
}
这里,getInstance
变得有些像工场要领,我们接见它的时刻并不须要更新我们的每一部分代码。上面的FooSingleton
多是BasicSingleton
的之类,而且完成了一样的接口。
为何在单例中耽误实行被以为很主要呢?:
在C++中,它被用来让我们处理动态初始化实行递次的不可展望性,把控制权交给了顺序。
须要注重的是区分类的静态实例和单例的区分是很主要的。只管单例可以被完成成静态实例。然则同时也可以耽误组织,不须要斲丧资本也不会斲丧内存直到须要它的时刻再初始化。
假如我们有一个可以被直接初始化的静态对象,我们须要确保代码是根据递次实行的。(比方,车的对象初始化的时刻车轮必需已存在)而且它在你有许多资本文件的时刻不会变大。
单例和静态对象都很有效,然则不能过分运用。就像不能过分运用其他形式一样。
实践中,当我们在全部体系中只须要一个对象与其他对象通讯的时刻,单例形式黑白常有效的。下面就是单例在上下文中运用形式的一个例子:
var SingletonTester = (function () {
// options: an object containing configuration options for the singleton
// e.g var options = { name: "test", pointX: 5};
function Singleton( options ) {
// set options to the options supplied
// or an empty object if none are provided
options = options || {};
// set some properties for our singleton
this.name = "SingletonTester";
this.pointX = options.pointX || 6;
this.pointY = options.pointY || 10;
}
// our instance holder
var instance;
// an emulation of static variables and methods
var _static = {
name: "SingletonTester",
// Method for getting an instance. It returns
// a singleton instance of a singleton object
getInstance: function( options ) {
if( instance === undefined ) {
instance = new Singleton( options );
}
return instance;
}
};
return _static;
})();
var singletonTest = SingletonTester.getInstance({
pointX: 5
});
// Log the output of pointX just to verify it is correct
// Outputs: 5
console.log( singletonTest.pointX );
只管单例在这里运用时有效的,然则常常当我们须要在javascript中运用它的时刻,每每意味着我们应当从新审阅我们的设想啦。
他们每每意味着体系的模块要不就是耦合过紧啦,要么逻辑延长的太大啦。单例的运用每每会让测试变得越发难题,由于存在隐蔽依靠,难以建立多个实例,难以找到根依靠等题目。