概述
单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。该模式下,在该实例子不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例;如果实例已经存在,它会返回该对象的应用。
实现方法
ES5
var Singleton = function() {
this.instance = null;
}
//核心方法,获取或创建实例的方法
Singleton.getInstance = function() {
if(!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
//a2
var a1=Singleton.getInstance();
ES6
class Singleton{
constructor(){
this.instance=null;
}
//静态方法
static getInstance(){
if(!this.instance){
this.instance=new Singleton();
}
return this.instance;
}
}
//调用
var a2=new Singleton.getInstance();
应用场景
全局唯一性消息框(对话框):场景要求用户点击弹出按钮弹出一个消息框,点击关闭按钮消息框消失。对于没有使用过设计模式的开发者可能有这样的思路:如在页面提前装载消息框,用户点击弹出或关闭弹出按钮时设置元素的显示状态,即display
样式。这个方法有这些缺点:消息框需要在页面加载完成后就要初始化好;用户不需要消息框的时候DOM元素还存在;使用单例设计模式可以在用户点击弹出按钮时才创建消息框,并追加到页面中,点击关闭消息框时把该DOM元素移除并销毁实例子。但是也有这些缺点:添加和移除DOM元素比修改DOM元素的display
样式更消耗性能。
<!DOCTYPE HTML>
<html>
<title>单例设计模式</title>
<head>
<meta charset="utf-8">
<style type="text/css">
.msg-mask {
position: absolute;
background: #000;
opacity: 0.5;
height: 40px;
top: 50px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
}
.msg-mask>.msg-body {
display: flex;
align-items: center;
justify-content: center;
padding: 0 50px;
color: #fff;
}
</style>
</head>
<body>
<h2>本例使用单例的思想实现需要动态的向页面追加DOM元素的功能,并确保追加DOM元素时只追加一次。</h2>
<h3>传统方法:</h3>
<button onclick="showNormalMsg()">打开消息框</button>
<button onclick="closeNormalMsg()">关闭消息框</button>
<h3>单例方法:</h3>
<button onclick="showSingletonMsg()">打开消息框</button>
<button onclick="closeSingletonMsg()">关闭消息框</button>
<script type="text/javascript">
function initMsg() {
const msgTemplate = `
<div class="msg-mask" id="normalMsg" style="display:none">
<div class="msg-body">消息内容</div>
</div>
`;
document.body.innerHTML += msgTemplate;
}
//初始化对话框
initMsg();
function showNormalMsg() {
document.getElementById('normalMsg').style.display = "flex";
}
function closeNormalMsg() {
document.getElementById('normalMsg').style.display = "none";
}
</script>
<script type="text/javascript">
class SingletonMsg {
constructor() {
this.instance = null;
}
static show() {
if (!this.instance) {
this.instance = new SingletonMsg();
const msgTemplate = `
<div class="msg-mask" id="singletonMsg">
<div class="msg-body">消息内容</div>
</div>
`;
document.body.innerHTML += msgTemplate;
}
return this.instance;
}
static close(){
if(this.instance){
document.body.removeChild(document.getElementById('singletonMsg'));
}
this.instance=null;
}
}
function showSingletonMsg() {
SingletonMsg.show();
}
function closeSingletonMsg() {
SingletonMsg.close();
}
</script>
</body>
</html>
总结
对于使用全局缓存,全局唯一或高频操作的使用场景,使用单例设计模式可以节省内存,减少资源消耗。然而单例模式在前端的使用场景和案例相对较少,常见于后端的数据库单例连接与数据库线程池连接等使用场景,桌面开发中的单窗口实例。前端开发者应该根据需要慎重使用单例设计模式,不要一味追求设计模式而导致开发速度的减缓,影响代码的维护。