JavaScript设计模式之单例模式

单例模式在前边的闭包中有实现过一部分。它的核心是确保只有一个实例,并且提供全局访问点。单例模式的实现主要是利用闭包来保存实例,如果实例已经存在,就使用该实例,如果不存在,则执行相应的函数来创建实例。

一、单例模式在实战中最常见的就是创建弹窗:

常用的创建弹窗的方法主要有以下几种:

1、页面初始化的时候,创建好一个隐藏的弹窗,当用户需要弹窗显示时,再修改样式,让其显示。

<body>
    <input type="button" value="打开弹窗" id="open" />

    <script>
    // 初始化渲染弹窗
    var dialogLayer = (function (){
	  var div = document.createElement('div');
	  div.innerHTML = '我是弹窗';
	  div.style.display = 'none';
	  document.body.appendChild(div);
	  return div;
    })();

    var oOpen = document.getElementById('open');
    
    // 按钮操作时修改样式
    oOpen.onclick = function (){
	  dialogLayer.style.display = 'block';
    }
    </script>
</body>

这种方式在页面初始化时,弹窗即被创建好添加到页面中了。但是如果该弹窗不是绝对会被使用的,那这些dom节点可能会被浪费。

2、用户需要弹窗显示时,创建弹窗并显示,隐藏时修改样式把弹窗隐藏。后续再显示隐藏,皆修改样式来控制。这种方式相对上一种,性能上要更加优化。下面这种写法是在上面的代码基础上做了简单的修改:

<body>
    <input type="button" value="打开弹窗" id="open" />

    <script>
    // 创建弹窗
    var createDialogLayer = function (){
        var div = document.createElement('div');
        div.innerHTML = '我是弹窗';
        div.style.display = 'none';
        document.body.appendChild(div);
        return div;
    };

    var oOpen = document.getElementById('open');
    var dialogLayer;  


    // 按钮操作时创建弹窗并修改样式
    oOpen.onclick = function (){
        // dialogLayer保证该弹窗是惟一的
        if(!dialogLayer){
  	    dialogLayer = createDialogLayer();
        }
        dialogLayer.style.display = 'block';
    }
    </script>
</body>

这种写法,引入了变量dialogLayer,是为了保证弹窗的惟一,否则会创建多个弹窗。但是它需要在点击操作的时候,做弹窗惟一性的判断,这在模块封装中是不太合理的。下面参考前边闭包的例子改写一下:

// 创建弹窗模块
var createDialogLayer = (function (){
	var div;  

	return function (){
		if(!div){  // 保证实例的单一性
                        // 创建弹窗
			div = document.createElement('div');
			div.innerHTML = '我是弹窗';
			div.style.display = 'none';
			document.body.appendChild(div);
		}
		return div;
	}
})();

var oOpen = document.getElementById('open');


// 按钮操作时创建弹窗并修改样式
oOpen.onclick = function (){
	var dialogLayer = createDialogLayer(); 
	dialogLayer.style.display = 'block';
}

这种写法跟闭包中的示例非常相似,在闭包中也提到了另一种可能更常用的写法,也比较了二者的区别,如果不清楚的可以去设计模式的闭包那节再了解一下。

如果要写其他类似的功能模块,完全可以按这个套路写出来。但是这种写法还存在一个问题,那就是创建对象的业务代码,与管理是否是单例的逻辑混在了一起。这里既然说的是设计模式,那就需要把这类问题的解决方案抽象出来,做到职责单一。

// 控制只可创建一个实例
var single = function (fn){
	var res;  // 存储实例
	return function (){
		// 如果res有值,则说明该实例已存在,则直接返回;否则执行函数,创建实例。
		return res || (res = fn.call(this, arguments));
	}
}

// 创建弹窗的业务逻辑
var createDialogLayer = function (){
	var div = document.createElement('div');
	div.innerHTML = '我是弹窗';
	div.style.display = 'none';
	document.body.appendChild(div);
	return div;
}

var dialogLayer = single(createDialogLayer);

var div1 = dialogLayer();
var div2 = dialogLayer();

console.log(div1 === div2);  // true

在这里,把业务代码和管理单例的代码分离开,如果后续要创建其他类似的单例对象,只需编写相应的业务逻辑即可。管理单例的single方法可以作为一个通用的方法,在任何需要的时候调用。

设计原则,理论比较枯燥,这里会穿插在设计模式中,根据实例来理解设计原则:

JS中主要的设计原则有这几种:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则、最少知识原则。

在单例模式中,就提到了单一职责原则。它可以降低单个方法的复杂度,按照职责把对象分解成更小的粒度,有利于代码的复用。但是这也有一些缺点,就是会增加代码编写的复杂度。这个在单例模式中主要体现在业务代码和管理单例代码的拆分上,虽然做到了职责单一,但是增加了代码的复杂度。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值