What
保证一个类只有一个实例,并为其提供一个访问它的全局访问点。
Why
有一些对象我们往往只需要一个,比如线程池、全局缓存、登录浮窗等。对于这些对象可以采用单例模式来构建,避免多次创建浪费资源。
How
单例模式只需要创建一个对象,因此在创建对象时,首先判断是否有创建的对象,如果有就直接返回该对象,否则生成一个新对象。例如
let instance;
function Single(name){
if(instance){
// 后面的创建走这儿
return instance;
}else{
// 第一次创建走这儿
this.name = name;
if(instance === undefined){
instance = this;
}
}
}
Single.prototype = {
constructor : Single,
// methods...
}
将上面的代码直接放在全局下很容易造成命名空间污染。这时候我们可以再改进一下。此时instance
因为闭包一直存在着,并指向Single
的实例对象
var Single = (function(){
let instance;
function Single(name){
if(instance){
// 后面的创建走这儿
return instance;
}else{
// 第一次创建走这儿
this.name = name;
if(instance === undefined){
instance = this;
}
}
}
Single.prototype = {
constructor : Single,
// methods...
}
return Single;
})()
若是这个类既可以产生单例对象,又要构造普通的类。这是我们可以引入代理类来构造单例对象
function Single(name){
this.name = name;
}
Single.prototype = {
constructor : Single,
// methods...
}
const ProxySingle = (function(){
let instance;
return function(fn,...argus){
if(!instance)
instance = new fn(...argus);
return instance
}
})();
在实际运用中,在需要创建的时候才创建的单例被称为惰性单例
function getSingle(fn){
let result;
return function(){
return result || (result = fn.apply(this,arguments))
}
}
总结
单例模式针对的是只需要一个实例的类。构造单例对象时,先创建一个标志instance
用来表示类的唯一实例,并用闭包来保存。每次创建实例时,判断instance
对象是否存在,不存在则创建一个实例,否则返回该对象。单例模式还可以用于只需要一个返回值的函数,利用高阶函数来保存函数的返回值。