[读书笔记] JavaScript设计模式: 单例模式
单例模式:保证一个类只有一个实例,并提供一个可以访问它的全局访问点。
一种简单、方便的写法就是用一个变量来标识当前类是否已经创建过对象,如果有,则返回已经创建好的对象,否则创建一个新对象,并将其返回。
var Singleton = function(name) { this.name = name; this.instance = null; } Singleton.prototype.getName = function() { alert(this.name); } Singleton.getInstance = function(name) { if (!this.instance) { this.instance = new Singleton(name); } return this.instance }
但是上述写法有一个问题,那就是使用Singleton这个类的时候,必须参考API文档,否则使用者不知道必须通过getInstance()方法而不是通过new的方式来获取对象,这就是增加了这个类的“不透明”性。
修改上述实现方式,使其变得“透明”些。
var Singleton = (function() { var instance = null; var Singleton = function(name) { if (!instance) { this.name = name; instance = this; } return instance; } Singleton.prototype.getName = function() { alert(this.name) } return Singleton; })()
修改后的Singleton类使用起来和其他的类没有区别,只要new Singleton('name')就可以了,但是上述写法也有一点小问题,那就是在Singleton的构造函数中做了两件事,一是创建对象并初始化name等变量,二是保证了该类只会存在一个对象,违反了设计原则中的“单一职责原则”的概念。如果后续要将Singleton改为非单例类,就必须要修改Singleton的构造函数。
为了使职责分的更加清楚,我们引入代理的方式来实现单例。
var Manager = function(name) { this.name = name; } Manager.prototype.getName = function() { alert(this.name); } var Singleton = (function() { var instance; return function(name) { if (!instance) { instance = new Manager(name) } return instance } })()
通过引入代理类,保证了各个类之间的职责单一。
上述是通过类的方式来创建单例对象,在其他语言中经常会看到这样的写法,如Java,C#等。但是JavaScript其实是一门无类(class-free)的语言,想要一个对象,直接创建就可以了,没有必要先创建类,再通过类创建对象,这样做无异于穿棉衣洗澡。所以说基于“类”的单例在JavaScript中其实并不适用。
在实际项目中经常会用到摸态框,一般来说,一个页面的模态框是唯一的,最常见的实现方式有以下两种方式:
- 在页面加载完成的时候便创建好模态框,当然这个模态框是隐藏的
- 当真正需要显示模态框时再创建
第一种方式简单,但是可能会浪费DOM元素,因为部分用户可能一直用不到这个模态框。第二种方式就需要用到将要学习的惰性单例。
var getSingle = (function() { var instance; return function(fn) { return instance || (instance = fn.apply(this, arguments)); } })() var createModal = function() { var div = document.createElement('div'); div.innerHTML = 'modal'; document.body.appendChild(div); return div; }
将getSingle方法提取出来,以后不光可以用于createModal,createXhr,createIframe等等都可以与getSingle组合使用。