什么是单例模式

单例(Singleton)模式限制了类的的实例化次数只能是一次。在实例不存在的情况下,可以通过一个方法创建一个新的实例;如果实例已经存在,那么它会返回该实例对象的引用。

单例VS静态类(或对象)

Singleton不同于静态类(或对象),因为我们可以推迟它的初始化,因为可能在初始化时需要一些其他相关的上下文信息。
而静态对象(如javascript plain object)允许被重新赋值而遭到破坏,故在某些特定场景下可使用单例模式来取代静态类。

简单实现单例模式

  1. var Singleton = (function (params) {
  2. var instance;
  3. function init () {
  4. // 私有变量
  5. var privateAttr = 'i am privateAttr'
  6. return {
  7. // 公共方法
  8. publicMethod: function () {
  9. console.log('I am public method')
  10. },
  11. getPrivateAttr: function () {
  12. return privateAttr
  13. }
  14. }
  15. }
  16. return {
  17. // 获取实例
  18. getInstance: function () {
  19. if (!instance) {
  20. instance = init()
  21. }
  22. return instance
  23. }
  24. }
  25. })()
  26. // 我们可以通过如下的方式获取引用
  27. var instance = Singleton.getInstance()
  28. var instance2 = Singleton.getInstance()
  29. instance.getPrivateAttr() // return i am privateAttr'
  30. instance.publicMethod() // I am public method
  31. console.log(instance === instance2) // true

推迟初始化的单例模式

  1. var Singleton = (function () {
  2. var instance;
  3. function init (params) {
  4. // 私有变量
  5. var userName = params.userName
  6. return {
  7. getUserName: function () {
  8. return userName
  9. }
  10. }
  11. }
  12. return {
  13. // 获取实例
  14. getInstance: function (params) {
  15. if (!instance) {
  16. instance = init(params)
  17. }
  18. return instance
  19. }
  20. }
  21. })()
  22. // 我们可以在ajax获取用户上下文之后初始化示例,并设置对应的userName
  23. var instance = Singleton.getInstance({userName: 'John'})
  24. instance.getUserName() // return 'John'
  25. var instance2 = Singleton.getInstance()
  26. instance2.getUserName() // return 'John'
  27. console.log(instance === instance2) // true

业务场景的实际应用

  1. 全局提示消息

假设页面会同时发出2个ajax请求,后端在用户未登录的情况下,会返回给前端并提示登录超时,假设前端ajax请求里封装了相关代码如下:

  1. error: function (status) {
  2. if (status === 'loginerror') {
  3. Common.errorDialog('登录失败请重试')
  4. }
  5. }

假设Common.errorDialog里封装的方法不是单例,而是每次都创建一个错误消息对话框,那么此时有可能会出现2个错误相同的提示对话框,而如果在这种场景下我们把errorDialog改造成单例模式,那么就可以避免重复出现对话框的问题。

  1. 表格中的参照Modal

通常企业级应用我们在表格的某些字段需要点击后出现一个Modal对话框进行数据的选取(比如人员参照),简单的实现可能会在每一行的人员单元格都放置一个参照组件,而每个参照组件可能是各自管理自己的弹出Modal。如果表格的数据量非常大,比如1000行,那就可能会出现1000个Modal实例。如果我们用单例模式来改造,在弹出Modal时每次都重用这一个Modal实例(一般页面中同一时刻界面上只会显示一个Modal),那么对数据量大的表格组件的性能提升将会是巨大的。

参考文献

[1]Addy Osmani著 徐涛译.JavaScript设计模式.北京:人民邮电出版社,2013,6