持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天
介绍
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
使用场景
-
要求生产唯一序列号。
-
WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
-
创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
-
在ES6中,import 引入的模块是会自动执行的,但是有的时候我们可能会重复引入一个模块,但是这个时候不会执行多次,因为import就用到了SIngleton模式。
应用实践
闭包方法实现
var SingleInstance = (function () {
let instance
// 获取当前实例
let getInstance = function (name) {
this.name = name
}
// 返回一个创建单例的函数
return function (name) {
return instance || (instance = new getInstance(name)) }
})()
//创建
const item1 = SingleInstance('test')
const item2 = SingleInstance('test')
console.log(item1===item2) // true,是同一个实例
原型方法实现
const SingleInstance = function () { this.instance = null;
};
SingleInstance.getInstance = function (name) {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
};
//获取实例
const item1 = SingleInstance.getInstance('test');
const item2 = SingleInstance.getInstance('test');console.log(item1===item2) // true,是同一个实例
类方式实现
class SingleInstance { constructor(name) {
this.name = name
this.instance = null
}
static getInstance(name) {
if (!this.instance) {
this.instance = new Single(name)
}
return this.instance
}
}
//获取实例
const item1 = SingleInstance.getInstance('test')
const item2 = SingleInstance.getInstance('test')
console.log(item1===item2) // true,是同一个实例
项目应用
创建一个唯一的dialog弹窗
html部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button id="btn1">点我创建新窗口</button>
<button id="hide">点我隐藏</button>
</body>
</html>
js部分
const btn1 = document.querySelector('#btn1');
const createWindow = (() => {
let div = null;
return (words) => {
if (!div) {
div = document.createElement('div');
div.innerHTML = words
div.className = 'common-box';
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
})();
btn1.addEventListener('click', () => {
let box = createWindow('content');
box.style.display = 'block';
}, false);
//隐藏
document.querySelector('#hide').addEventListener('click', () => {
document.querySelector('.common-box').style.display = 'none';
}, false);
汇总
有点特性
-
在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例。
-
由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
-
避免对共享资源的多重占用。
-
系统中需要一个唯一的对象去控制、管理和分享系统的状态,或者执行某一个特定的任务又或是实现某一个具体的功能。在我们的前端开发中,最常见的就是应用的状态管理对象,比如 Vuex和 Redux。
-
全局只有一个实例,提供统一的访问与修改,保证状态功能的一致性。
缺点弊端
-
由于单利模式中没有抽象层,因此单例类的扩展有很大的困难
-
单例类的职责过重,在一定程度上违背了
单一职责原则。 -
不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误。
-
单例模式的滥用会造成跟全局变量一样的一些问题。比如会增加代码的耦合性,因为单例模式全局都是可以访问到的,那么我们就很有可能在很多个地方使用这个唯一的对象
-
单例模式隐藏了它所需要的依赖。它的依赖封装在内部,对于外部的使用者来说它是一个黑盒。使用者并不知道初始化这个单例需要那些依赖。