设计模式之单例模式
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。也可以这样认为,单例只是全局的一个别称。
透明的单例模式
透明的单例模式:下面,我们将使用CreateDiv单例类,它的作用是负责在页面中创建唯一的div节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   | class CreateDiv {          private static instance:CreateDiv          private constructor(public html:string){                  this.init()     }               public static createDivInstance(){                           if(!this.instance){             this.instance = new CreateDiv('a div')           }         return this.instance     }          private init(){         const div = document.createElement('div')         div.innerHTML = this.html         document.body.appendChild(div)     }    }
  let a = CreateDiv.createDivInstance() let b = CreateDiv.createDivInstance() console.log(a===b)	
  | 
 
代理单例模式
在上段代码中,CreateDiv类实际上负责了两件事情。
第一:创建对象和初始化init方法;第二:保证只有一个对象
这不符合“单一职责原则”的概念,假如我们某天需要利用这个类,在页面中创建千千万万的div,即要让这个类从单例类变成一个普通的可产生多个实例的类,那我们必须得改写CreateDiv构造函数,把控制创建唯一对象的那一段去掉,这种修改会给我们带来不必要的烦恼。
现在我们通过引入代理类的方式,来解决上面提到的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   | class CreateDiv {
      constructor(public html: string) {         this.init()     }     private init() {         let div = document.createElement('div')         div.innerHTML = this.html         document.body.appendChild(div)     }
  }
  class ProxySingletonCreateDiv {
      private static instance: CreateDiv
      public static getInstance(text: string) {         if (!this.instance) {             this.instance = new CreateDiv(text)         }         return this.instance     } }
 
 
  const a = ProxySingletonCreateDiv.getInstance('diva') const b = ProxySingletonCreateDiv.getInstance('divb') console.log(a == b) 
  | 
 
惰性单例
惰性单例:是在需要的时候才创建对象实例。
实际上在文章开头就使用过这种技术,instance实例对象总是在我们调用CreateDiv.createDivInstance时候才被创建,上述都是基于”类“的单例模式,这在javascript中并不适用,我们应该使用函数+闭包的方式实现惰性单例。
下面以网页中的登录弹窗为例:
首先在用户进入网页时:如果登录弹窗一开始就被创建好,在用户只浏览不进行登录的情况下,这样会白白浪费一些DOM节点,只有用户点击登录按钮时才开始创建该弹窗;
还有就是该弹窗在页面是唯一的,不可能出现同时存在两个登录窗口的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   |  let createLoginLayer = (function(){     let div:HTMLDivElement;     return function(){         if(!div){             div=document.createElement('div')             div.innerHTML = '我是登录弹窗'             div.style.display = 'none'             document.body.appendChild(div)         }         return div     } })()
  let btn = document.getElementById('loginBtn') btn?.addEventListener('click',()=>{     let loginLayer = createLoginLayer();     loginLayer.style.display = 'block' })
 
  |