什么是单例模式?怎么生成单例类? - 1/14
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。比如线程池、全局缓存、浏 览器中的 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设计模式与开发实践》