当 js 碰到设计模式之单例模式

单例模式是我在开发过程中使用最多的设计模式。

起因

之前写 express 引入 mysql,在不同的文件中要使用 mysql 的时候都要 new 一次才能拿到实例。这就意味着有可能有多个 mysql 实例存在。

能不能共用同一个实例呢?能,使用单例模式。

[客户端甚至可能没有意识到它们一直都在使用同一个对象。](https://refactoringguru.cn/design-patterns/singleton)

简单实现

奈何我 js 只会 ES6,用 ES6 实现,先看代码:

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton {
static getInstance() {
this.instance = this.instance || this;
return this.instance;
}
}

const test1 = Singleton.getInstance();
const test2 = Singleton.getInstance();

console.log(test1 === test2);

这里面没有看到new,而是用一个static修饰的init 静态方法。因为如果调用newSingleton会先执行constructor构造函数,返回一个新的实例。所以在常规的单例模式中,将默认构造函数设为私有, 防止其他对象使用单例类的 new 运算符。只能通过静态方法getInstance获取到实例。

[单例模式结构](https://refactoringguru.cn/design-patterns/singleton)

然而不幸的是,js 中并没有私有修饰符,所以使用者还是用new得到一个新的实例。

传参

如果想初始化参数,那就要改一下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Singleton {
constructor(name) {
this.name = name;
}

static getInstance(name) {
// this.instance = this.instance || this;
if (!this.instance) {
this.instance = new this(name);
}
return this.instance;
}
}

const test1 = Singleton.getInstance("x");
const test2 = Singleton.getInstance();

console.log(test2.name); // x

优缺点

优点当然是只有一个实例对象了。

缺点:在多线程的环境下需要一些特殊处理,避免多线程多次创建单例对象。