什么是单例模式
单例(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 methodconsole.log(instance === instance2) // true
推迟初始化的单例模式
var Singleton = (function () {var instance;function init (params) {// 私有变量var userName = params.userNamereturn {getUserName: function () {return userName}}}return {// 获取实例getInstance: function (params) {if (!instance) {instance = init(params)}return instance}}})()// 我们可以在ajax获取用户上下文之后初始化示例,并设置对应的userNamevar 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
