单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。比如线程池、全局缓存、浏 览器中的 window 对象等。
实现单例模式
实现一个标准的单例模式,其实用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。
v1.0,直觉思路
直接按照思路写
let instance;
function X(name) {
if (instance) {
return instance;
}
this.name = name;
instance = this;
}
var a = new X("a");
var b = new X("b");
// true
console.log(a === b);
v2.0,让变量内部化
使用闭包让 instance 不暴露在全局,返回的函数是真正的类
// 其实就是把上面的代码用个自执行函数包起来,末了返回上面X的实体内容
var X = (function() {
let instance;
return function(name) {
if (instance) {
return instance;
}
this.name = name;
instance = this;
};
})();
var a = new X("a");
var b = new X("b");
console.log(a === b);
v3.0,升级加个代理类
上面代码中,X 的构造函数实际上负责了两件事情。
- 创建对象
- 保证只有一个对象。
这违反了“单一职责原则”的概念,所以我们拆开试试,普通的类就是普通的类,如果需要单例的类,创建一个新类,这个新类就是一个代理类。
// 普通的X类
function X(name) {
this.name = name;
}
// 代理类,实际返回的是X的实例
var X_Proxy = (function() {
let instance;
return function(...args) {
if (instance) {
return instance;
}
// 其实就是把上个版本的这里改成生成的实例而已啦
instance = new X(...args);
// !!!注意,这里返回的是X的实例
return instance;
};
})();
var a = new X_Proxy("a");
var b = new X_Proxy("b");
console.log(a === b);
v3.1,稍微优化下 if 那边
var X_Proxy = (function() {
let instance;
return function(...args) {
// 就是if这里稍微优化下啦,没啥技术含量
if (!instance) {
instance = new X(...args);
}
return instance;
};
})();
v4.0,抽象出生成单例模式的函数
任何一个类,都可以增加一个单例代理类,这样我们可以写一个函数,专门生成单例代理类。
// 其实把上个版本的X_Proxy中的X改成fn,作为参数传进去,末了去掉自执行即可
var Create_Single_Proxy = function(fn) {
let instance;
return function(...args) {
if (!instance) {
instance = new fn(...args);
}
return instance;
};
};
// 任意一个普通类
function X(name) {
this.name = name;
}
// 生成其 单例代理类
var X_Proxy = Create_Single_Proxy(X);
var a = new X_Proxy("a");
var b = new X_Proxy("b");
console.log(a === b);
v4.1,精炼下Create_Single_Proxy
var Create_Single_Proxy = function(fn) {
let instance;
return function(...args) {
// 就是这里稍微优化下啦,别忘了赋值
return instance || (instance = new fn(...args));
};
};
以上参考《Javascript设计模式与开发实践》