设计模式-单例模式
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象等。
试想一下这种场景:
当我们点击登录按钮,页面就出现一个登录弹窗,而弹窗是唯一的,每次点击登录都会弹出一个相同的弹窗。
先看一下下面的实现
1 var loginLayer = (function(){ 2 var div = document.createElement('div'); 3 div.innerHTML = '我是登录弹窗'; 4 div.style.display = 'none'; 5 document.body.appendChild(div); 6 return div; 7 })() 8 9 document.getElementById('loginBtn').onclick = function(){ 10 loginLayer.style.display = 'block'; 11 }
虽然每次点击登录按钮都能实现显示登录弹窗,但是即使没有点击登录也会创建登录窗口的dom,就会造成浪费。
那对上面出现的问题进行优化一下吧
1 function createLoginLayer(){ 2 const div = document.createElement('div'); 3 div.innerHTML = '我是登录弹窗'; 4 div.style.display = 'none'; 5 document.body.appendChild(div); 6 return div; 7 } 8 9 document.getElementById('loginBtn').onclick = () => { 10 const loginLayer = createLoginLayer(); 11 loginLayer.style.display = 'block' 12 }
上面的代码解决了初始化创建登录dom的问题,但是又出现另一个问题,就是每次点击登录都会创建一个登录浮窗,频繁创建Dom造成浪费。实际上我们只要创建一个登录浮窗。
单例模式
1 var createLoginLayer = (function(){ 2 let div; 3 return function(){ 4 if(!div){ 5 div = document.createElement('div'); 6 div.innerHTML = '我是登录弹窗'; 7 div.style.display = 'none'; 8 document.body.appendChild(div); 9 } 10 return div 11 } 12 })() 13 14 document.getElementById('loginBtn').onclick = function(){ 15 var loginLayer = createLoginLayer() 16 loginLayer.style.display = 'none'; 17 }
这种方式解决了上面出现的问题,是一种比较理想的实现方式。
但是这段代码同样违反单一职责原则的,创建对象和管理单例都放在createLoginLayer内部,再比如我们如果需要再创建一个iframe,就需要照抄一份createLoginLayer 函数,至此我们需要把不变的部分分离开来,管理单例的逻辑进行抽象,逻辑始终是一样的
// createSingle 用来管理单例 const createSingle = (function(){ const instance = {} return function(fn){ console.log('fn', fn.name) if(!instance[fn.name]){ instance[fn.name] = fn.apply(this, arguments) } } })() const createIframe = function () { const iframe = document.createElement('iframe') document.body.appendChild(iframe) iframe.style.display = 'none' return iframe } const createLoginLayer = function(){ const div = document.createElement('div'); div.innerHTML = this.name; div.style.display = 'none'; document.body.appendChild(div); }
document.getElementById('loginBtn').onclick = () => {
const createSingleLoginLayer = createSingle(createLoginLayer.bind({name: '我是登录弹窗'}))
const createSingleIframe = createSingle(createIframe)
createSingleLoginLayer.style.display = 'block'
createSingleIframe.style.display = 'block'
}
将创建createLoginLayer / createIframe职责与管理单例对象createSingle 进行拆分职责分离,符合单一职责原则
通过闭包的方式进行存储,不会多次创建同时只会在点击时创建,并且可复用
浙公网安备 33010602011771号