JavaScript设计模式(4.5单例模式慵性单例)

216 阅读3分钟

「这是我参与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';
	};

在这个例子中,我们把创建实例对象和创建管理对象分离开来,这两个方法互相分离可以独立变换但是互不影响,但是又可以联合起来使用,这是不是很奇妙的一件事情。

小结

单例模式是设计模式中的第一个模式,简单来讲就是把创建对象和管理对象分布在两个不同的方法里面,这两个方法组合起来具有单例的威力!!