设计模式 2024 年 3 月 19 日
设计模式-单例模式
设计模式-单例模式
单例模式
保证一个类仅有一个实例,并且提供一个访问它的全局访问点,这样的模式就是单例模式。说人话就是:人们称呼的老婆,通常是特指某一个人(正常人)、某一个物(二刺螈)、某几个人(非正常人)或者某几个物(煞笔二刺螈)来构成。
我们要尊重物种的多样性(XP),但现在特指是“new”出来的一个实例(实例是通过创建出来的)。
单例模式是最通俗易懂,容易上手的一种模式,同时有广泛使用的场景,比如自己封装或着使用别人封装的开源工具类。
class SingletonFake{
init() {
console.log('我是一个单例类!')
}
}
const s1 = new SingletonFake()
const s2 = new SingletonFake()
s1 === s2 // false
为什么是false,s1、s2之间没有任何瓜葛,都是熟悉的陌生人,各自为独立的对象,各自独占一块属于自己的内存空间。
但是我们想要做的是s1和s2,甚至s3都是返回的同一个实例。(即,无论尝试创建多少次,始终返回第一次已经创建好了的实例)
要做的到这一点,需要有一个具备判断自己是否已经创建过一个实例的能力。我们可以整理成静态方法写入函数体内。
class Singleton {
init() {
console.log('我是一个单例类!')
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton()
}
return Singleton.instance
}
// #getInstance2() {
// if (!Singleton.instance) {
// Singleton.instance = new Singleton()
// }
// return Singleton.instance
// }
}
const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()
const s3 = Singleton.getInstance2() // Uncaught TypeError: Singleton.getInstance is not a function
// 因为#为private私有方法,只能在类内部访问
s1 === s2 // true
如果要每一种方式来尝试创建Singleton类的实例,都只能得到同一个实例。那么我们可以完善这个demo
class Singleton {
static #instance;
value;
constructor(value) {
if (Singleton.#instance) {
return Singleton.#instance
}
this.value = value // 让传入的value设置该类里实例的属性进行赋值,开始干活了
Singleton.#instance = this // 存储类的私有静态引用,确保将来任何创建实例都返回这个创建的实例
}
init() {
console.log('我是一个单例类!')
}
static getInstance(value) {
if (!Singleton.#instance) {
Singleton.#instance = new Singleton(value);
}
return Singleton.#instance;
}
}
const s1 = new Singleton()
const s2 = new Singleton()
const s3 = Singleton.getInstance()
console.log('s1 === s2', s1 === s2) // true
console.log('s1 === s3', s1 === s3) // true
也可以用闭包的方式来实现
Singleton.getInstance = (function () {
let instance = null
return function () {
if (!instance) {
instance = new Singleton()
}
return instance
}
})()
因为闭包的特性,所以instance本身就只能在内部被访问,所以不用声明单独的静态属性来防止污染外部环境的变量。
简单说下步骤和解释
-
Singleton.getInstance = (function() { … })():这里定义了一个自执行的匿名函数(即 IIFE - Immediately Invoked Function Expression),它在定义后立即执行。它的返回值是一个函数,这个函数被赋值给 Singleton.getInstance。
-
let instance = null:在这个自执行函数的作用域内,定义了一个变量 instance 并初始化为 null。这个变量对外部是不可见的,只能通过 getInstance 方法访问,这就模拟了一个私有变量。
-
return function() { … }:自执行函数返回一个新的函数,这个函数是 getInstance 方法的实际实现。每次调用 Singleton.getInstance() 都会执行这个函数。
-
if(!instance) { … }:在返回的函数内部,首先检查 instance 变量是否为 null。如果是 null,说明还没有创建 Singleton 的实例。
-
instance = new Singleton():如果 instance 是 null,则创建 Singleton 类的一个新实例,并将其赋值给 instance 变量。这是单例的唯一实例。
-
return instance:返回 instance 变量,无论它是刚刚创建的还是之前已经存在的实例。
通过这种方式,Singleton.getInstance 方法始终返回同一个 Singleton 实例,无论它被调用多少次,从而实现了单例模式。这种模式的优点是它不仅隐藏了实例的创建逻辑,还确保了单例的私有性和唯一性。
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
作者: 保安 发表日期:2024 年 3 月 19 日