单例模式可能是设计模式里面最简单的模式了,虽然简单,但在我们日常生活和编程中却经常接触到,本节我们一起来学习一下。
单例模式(Singleton Pattern)又称为单体模式,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。
实现一
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance
}
Singleton.instance = this
}
static getInstance() {
if (Singleton.instance) {
return Singleton.instance
}
return Singleton.instance = new Singleton()
}
}
Singleton.instance = null
const instance1 = new Singleton()
const instance2 = new Singleton()
console.log(instance1 === instance2)
实现二(IIFE方式)
const Singleton = (function() {
let _instance = null // 存储单例
const Singleton = function() {
if (_instance) return _instance // 判断是否已有单例
_instance = this
this.init() // 初始化操作
return _instance
}
Singleton.prototype.init = function() {
this.foo = 'Singleton Pattern'
}
Singleton.getInstance = function() {
if (_instance) return _instance
_instance = new Singleton()
return _instance
}
return Singleton
})()
const visitor1 = new Singleton()
const visitor2 = new Singleton() // 既可以 new 获取单例
const visitor3 = Singleton.getInstance() // 也可以 getInstance 获取单例
console.log(visitor1 === visitor2) // true
console.log(visitor1 === visitor3) // true
实现三(块级作用域方式)
let getInstance
{
let _instance = null // 存储单例
const Singleton = function() {
if (_instance) return _instance // 判断是否已有单例
_instance = this
this.init() // 初始化操作
return _instance
}
Singleton.prototype.init = function() {
this.foo = 'Singleton Pattern'
}
getInstance = function() {
if (_instance) return _instance
_instance = new Singleton()
return _instance
}
}
const visitor1 = getInstance()
const visitor2 = getInstance()
console.log(visitor1 === visitor2)
// 输出: true
实现三 单例模式赋能
/* 功能类 */
class FuncClass {
constructor(bar) {
this.bar = bar
this.init()
}
init() {
this.foo = 'Singleton Pattern'
}
}
/* 单例模式的赋能类 */
const Singleton = (function() {
let _instance = null // 存储单例
const ProxySingleton = function(bar) {
if (_instance) return _instance // 判断是否已有单例
_instance = new FuncClass(bar)
return _instance
}
ProxySingleton.getInstance = function(bar) {
if (_instance) return _instance
_instance = new Singleton(bar)
return _instance
}
return ProxySingleton
})()
const visitor1 = new Singleton('单例1')
const visitor2 = new Singleton('单例2')
const visitor3 = Singleton.getInstance()
console.log(visitor1 === visitor2) // true
console.log(visitor1 === visitor3) // true
实现四 Proxy
/* Person 类 */
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
/* 单例模式的赋能方法 */
function Singleton(FuncClass) {
let _instance
return new Proxy(FuncClass, {
construct(target, args) {
return _instance || (_instance = Reflect.construct(FuncClass, args)) // 使用 new FuncClass(...args) 也可以
}
})
}
const PersonInstance = Singleton(Person)
const person1 = new PersonInstance('张小帅', 25)
const person2 = new PersonInstance('李小美', 23)
console.log(person1 === person2) // true
实现五 饿汉式与懒汉式
class FuncClass {
constructor() { this.bar = 'bar' }
}
// 饿汉式
const HungrySingleton = (function() {
const _instance = new FuncClass()
return function() {
return _instance
}
})()
// 懒汉式
const LazySingleton = (function() {
let _instance = null
return function() {
return _instance || (_instance = new FuncClass())
}
})()
const visitor1 = new HungrySingleton()
const visitor2 = new HungrySingleton()
const visitor3 = new LazySingleton()
const visitor4 = new LazySingleton()
console.log(visitor1 === visitor2) // true
console.log(visitor3 === visitor4) // true
单例模式的总结
单例模式主要解决的问题就是节约资源,保持访问一致性。
优点
- 单例模式在创建后在内存中只存在一个实例,节约了内存开支和实例化时的性能开支,特别是需要重复使用一个创建开销比较大的类时,比起实例不断地销毁和重新实例化,单例能节约更多资源,比如数据库连接;
- 单例模式可以解决对资源的多重占用,比如写文件操作时,因为只有一个实例,可以避免对一个文件进行同时操作;
- 只使用一个实例,也可以减小垃圾回收机制 GC(Garbage Collecation) 的压力,表现在浏览器中就是系统卡顿减少,操作更流畅,CPU 资源占用更少;
缺点
- 单例模式对扩展不友好,一般不容易扩展,因为单例模式一般自行实例化,没有接口;
- 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化;