「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
上回我们看到了单例模式,接下来我来给你大家简单聊一下单例模式中的慵性单例。
正文
实际上慵性单例指的是在需要创建的时候才创建对象实例,这是单例模式的一个重要点,在开发中非常有用。
打个比方,如果我们是webQQ的开发人员,当用户点击那个企鹅头像进行登录时,会弹出一个登录弹窗,这个弹窗显然是唯一的,不可能存在多个登录弹窗,那么我们可以选择在页面加载完成时便创建好这弹窗,显然这弹窗一开始是隐藏抓状态的,只有当用户点击时才会弹出显示,就像这样:
Singleton.getInstance = (function(){
var instance = null;
return function( name ){
if ( !instance ){
instance = new Singleton( name );
}
return instance;
}
})();
但是我们又会发现一些问题,当用户到这个webQQ网站只是想看一下新闻或者玩玩游戏什么的并不想进行登录操作,显然我们这里会白白浪费一个DOM节点,我们可以选择只有当用户点击的时候,才会创建一个登录弹窗:
<html>
<body>
<button id="loginBtn">登录</button>
</body>
<script>
var createLoginLayer = function(){
var div = document.createElement( 'div' );
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild( div );
return div;
};
document.getElementById( 'loginBtn' ).onclick = function(){
var loginLayer = createLoginLayer();
loginLayer.style.display = 'block';
};
</script>
</html>
问题总是不断地出现,这样做确实节省了DOM节点资源,但是我们会发现他与单例模式相违背,当用户多次点击页面地时候,会创建多次登录弹窗div,虽然我们可以设置一个X让用户进行删除窗口,但是频繁地操作创建删除显然是不合理的,也没有必要。
那怎么做到既满足单例模式又能节省DOM节点呢?
相信大佬们已经想到了解决的办法,就是创建一个变量来判断弹窗是否已经被创建,就好比我们第一段代码中的做法一样,这里我就不把代码写出来了。
通用的慵性单例
上面我们说了一个慵性单例,但是大家不妨想一想,那段代码明显违反单一的原则,管理对象和管理单例的逻辑都写在createLoginLayer里面,如果我们下次要添加一个iframe,那岂不是如法炮制又重新抄一遍createLoginLayer,这显然是又行的,看起来十分臃肿。我们需要把不变的分离出来,就像这样
var getSingle = function( fn ){
var result;
return function(){
return result || ( result = fn .apply(this, arguments ) );
}
};
这样我们不仅可以传入createLoginLayer,还能传入createIframe,createIframe,createXhr。,然后让getSingle返回一个新的函数,并且用一个变量result保存fn的计算结果。result在闭包中永远不会被摧毁,在将来的求情中,如果result已经被赋值,那么它将返回这个值
var createSingleLoginLayer = getSingle(function () {
var div = document.createElement('div');
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild(div);
return div;
});
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = 'block';
};
再创建一个iframe窗口
var createSingleIframe = getSingle( function(){
var iframe = document.createElement ( 'iframe' );
document.body.appendChild( iframe );
return iframe;
});
document.getElementById( 'loginBtn' ).onclick = function(){
var loginLayer = createSingleIframe();
loginLayer.src = 'http://baidu.com';
};
在这个例子中,我们把创建实例对象和创建管理对象分离开来,这两个方法互相分离可以独立变换但是互不影响,但是又可以联合起来使用,这是不是很奇妙的一件事情。
小结
单例模式是设计模式中的第一个模式,简单来讲就是把创建对象和管理对象分布在两个不同的方法里面,这两个方法组合起来具有单例的威力!!