一、什么是单例模式
单例模式的定义是,保证一个类仅有一个实例,并提供一个访问它的全局访问点。
有一些对象,比如线程池/全局缓存/浏览器中的 window
对象等等,我们只需要一个实例。下面将根据实际场景进行介绍。
二、实际场景
1. 登录浮窗
当我们单击登录按钮时,页面中会出现一个登录的浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。
1.1 传统做法
传统做法在页面加载完成时,就创建好登录浮窗,当用户点击登录按钮时,显示登录浮窗,实现代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<button id="loginBtn">登录</button>
<script type="text/javascript" src="index.js">
</script>
</body>
</html>
var loginLayer = (() => {
let div = document.createElement('div')
div.innerHTML = '我是登录弹窗'
div.style.display = 'none'
document.body.appendChild(div)
return div
})()
document.getElementById('loginBtn').onclick = () => {
loginLayer.style.display = 'block'
}
源码地址
上述代码有以下缺点:
在无需登录的情况下,也会新增登录浮窗的 DOM 节点,浪费性能。
现在优化一下,将代码改为,在用户点击登录按钮后,才新增登录浮窗的 DOM 节点。
代码如下:
var createLoginLayer = () => {
let div = document.createElement('div')
div.innerHTML = '我是登录弹窗'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
document.getElementById('loginBtn').onclick = () => {
const loginLayer = createLoginLayer()
loginLayer.style.display = 'block'
}
源码地址
上述代码也存在缺陷,具体如下:
每次点击登录按钮,都会创建一个登录浮窗,频繁的创建 DOM 节点更加浪费性能。
实际上,我们只需要创建一次登录浮窗。
1.2 单例模式
通过单例模式,重构上述代码。
const createLoginLayer = () => {
const div = document.createElement('div')
div.innerHTML = '我是登录弹窗'
div.style.display = 'none'
console.log(123)
document.body.appendChild(div)
return div
}
const createSingle = (function () {
var instance = {}
return function (fn) {
if (!instance[fn.name]) {
instance[fn.name] = fn.apply(this, arguments)
}
return instance[fn.name]
}
})()
const createIframe = function () {
const iframe = document.createElement('iframe')
document.body.appendChild(iframe)
iframe.style.display = 'none'
return iframe
}
const createSingleLoginLayer = createSingle(createLoginLayer)
const createSingleIframe = createSingle(createIframe)
document.getElementById('loginBtn').onclick = () => {
const loginLayer = createSingleLoginLayer
const iframe = createSingleIframe
loginLayer.style.display = 'block'
iframe.style.display = 'block'
}
源码地址
经过重构,代码做了以下优化:
- 将创建实例对象
createLoginLayer
/createIframe
的职责和管理单例对象createSingle
的职责分离,符合单一职责原则; - 通过闭包存储实例,并进行判断,不管点击登录按钮多少次,只创建一个登录浮窗实例;
- 易于扩展,当下次需要创建页面中唯一的
iframe
/script
等其他标签时,可以直接复用该逻辑。
三、总结
单例模式是一种简单但非常实用的模式,特别是惰性单例技术,在合适的时候才创建对象,并且只创建唯一的一个。更奇妙的是,创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才具有单例模式的威力。
作者:清汤饺子
链接:https://juejin.cn/post/6967956673453359140
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
转载请注明:有爱前端 » 设计模式-单例模式(一)