🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点 ## 简单的单例模式 ```javascript var Singleton = function(name){ this.name = name; this.instance = null; } Singleton.prototype.getName = function(){ return this.name; } Singleton.getInstance = function(name){ if(!this.instance){ this.instance = new Singeton(name); } return this.instance; } var a = Singleton.getInstance('1'); var b = Singleton.getInstance('2'); alert(a === b) // true // or var Singleton = function(name){ this.name = name; } Singleton.prototype.getName = function(){ return this.name; } Singleton.getInstance = (function(){ var instance; return function(name){ if(!instance){ instance = new Singleton(name); } return instance; } })(); ``` 通过`Singleton.getInstance`获取了`Singleton`的唯一对象,但是这么做,意义并不大。 ## 透明的单例模式 从这个类中创建对象时,用户可以像使用普通的一个类一样进行使用,其实就是不需要向上面一样,通过`Singleton.getInstance`进调用 ```javascript var CreateDiv = (function(){ var instance; var CreateDiv = function(html){ if(instance){ return instance } this.html = html; this.init(); return instance = this; } CreateDiv.prototype.init = function(){ var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); } return CreateDiv; })(); var a = new CreateDiv('1'); var b = new CreateDiv('2'); // a === b =>true ``` ## 用代理实现单例模式 ```javascript var CreateDiv = function(html){ this.html = html; this.init(); }; CreateDiv.prototype.init = function(){ var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); } var ProxySingletonCreateDiv = (function(){ var instance; return function(html){ if(!instance){ instance = new CreateDiv(html); } return instance; } })(); var a = ProxySingletonCreateDiv('1'); var b = ProxySingletonCreateDiv('2'); // a === b => true ``` 将`CreateDiv`剥离出来为单独的一个类,通过代理的方式去创建`CreateDiv`,两者结合就成为了单例模式,即`CreateDiv`负责正常的业务逻辑,`ProxySingleCreateDiv`负责创建单例 ## 惰性单例 在需要的时候才创建对象实例 ```javascript var createLoginLayer = (function(){ var div; return function(){ if(!div){ div = document.createElement('div'); div.innerText = '这是弹窗'; div.style.display = 'none'; document.body.appendChild(div); } return div; } })(); document.getElementById('loginBtn').onclick = function(){ var layer = createLoginLayer(); layer.style.display = 'block'; } ``` ## 通用的惰性单例 逻辑都是一致的,用一个变量来标志是否创建一个对象,是则返回。 ```javascript var obj; if(!obj){ obj = xxx } return obj; ``` 则对代码进行剥离,将创建单例的代码取出,业务代码也剥离出来; ```javascript var getSingleton = function(fn){ var result; return function(){ return result || (result = fn.apply(this, arguments)); } } var createLoginLayer = function(){ var div; return function(){ if(!div){ div = document.createElement('div'); div.innerText = '这是弹窗'; div.style.display = 'none'; document.body.appendChild(div); } return div; } }); var singletonCreateLoginLayer = getSingleton(createLoginLayer); document.getElementById('loginBtn').onclick = function(){ var layer = singletonCreateLoginLayer(); layer.style.display = 'block'; } ``` 创建实例对象的职责和管理单例的职责分别放置在两个方法里,这两个方法可以独立变化而互不影响。