什么是单例模式
单例(Singleton)模式限制了类的的实例化次数只能是一次。在实例不存在的情况下,可以通过一个方法创建一个新的实例;如果实例已经存在,那么它会返回该实例对象的引用。
单例VS静态类(或对象)
Singleton不同于静态类(或对象),因为我们可以推迟它的初始化,因为可能在初始化时需要一些其他相关的上下文信息。
而静态对象(如javascript plain object)允许被重新赋值而遭到破坏,故在某些特定场景下可使用单例模式来取代静态类。
简单实现单例模式
var Singleton = (function (params) {
var instance;
function init () {
// 私有变量
var privateAttr = 'i am privateAttr'
return {
// 公共方法
publicMethod: function () {
console.log('I am public method')
},
getPrivateAttr: function () {
return privateAttr
}
}
}
return {
// 获取实例
getInstance: function () {
if (!instance) {
instance = init()
}
return instance
}
}
})()
// 我们可以通过如下的方式获取引用
var instance = Singleton.getInstance()
var instance2 = Singleton.getInstance()
instance.getPrivateAttr() // return i am privateAttr'
instance.publicMethod() // I am public method
console.log(instance === instance2) // true
推迟初始化的单例模式
var Singleton = (function () {
var instance;
function init (params) {
// 私有变量
var userName = params.userName
return {
getUserName: function () {
return userName
}
}
}
return {
// 获取实例
getInstance: function (params) {
if (!instance) {
instance = init(params)
}
return instance
}
}
})()
// 我们可以在ajax获取用户上下文之后初始化示例,并设置对应的userName
var instance = Singleton.getInstance({userName: 'John'})
instance.getUserName() // return 'John'
var instance2 = Singleton.getInstance()
instance2.getUserName() // return 'John'
console.log(instance === instance2) // true
业务场景的实际应用
- 全局提示消息
假设页面会同时发出2个ajax请求,后端在用户未登录的情况下,会返回给前端并提示登录超时,假设前端ajax请求里封装了相关代码如下:
error: function (status) {
if (status === 'loginerror') {
Common.errorDialog('登录失败请重试')
}
}
假设Common.errorDialog里封装的方法不是单例,而是每次都创建一个错误消息对话框,那么此时有可能会出现2个错误相同的提示对话框,而如果在这种场景下我们把errorDialog改造成单例模式,那么就可以避免重复出现对话框的问题。
- 表格中的参照Modal
通常企业级应用我们在表格的某些字段需要点击后出现一个Modal对话框进行数据的选取(比如人员参照),简单的实现可能会在每一行的人员单元格都放置一个参照组件,而每个参照组件可能是各自管理自己的弹出Modal。如果表格的数据量非常大,比如1000行,那就可能会出现1000个Modal实例。如果我们用单例模式来改造,在弹出Modal时每次都重用这一个Modal实例(一般页面中同一时刻界面上只会显示一个Modal),那么对数据量大的表格组件的性能提升将会是巨大的。
参考文献
[1]Addy Osmani著 徐涛译.JavaScript设计模式.北京:人民邮电出版社,2013,6