为什么需要单例模式
在开发过程中,保持代码的正确性至关重要。主要有两个方面可以确保这一点:
- 唯一性保证:确保代码结构能强制执行标准,避免错误的产生。也就是说,你的代码只能按照规定的方式工作,从而防止出现不符合标准的代码。
- 错误提示:在开发阶段提供及时的错误提示。虽然不能绝对保证代码完全正确,但能在开发过程中发现并解决潜在的错误,避免这些错误流入生产环境。
核心思想
一个构造函数只能创建一个实例。通过这种方式,我们可以确保在整个应用程序中,某个类只有一个对象被创建。这样做的好处是可以减少资源消耗,控制对共享资源的访问,避免状态不一致等问题。
如果这些保证不到位,可能会导致错误的代码漏到用户端,增加调试和修复的成本。
实现单例模式的几种方法
1. 使用闭包(JavaScript)
在 JavaScript 中,可以使用闭包来模拟私有构造函数,从而实现单例模式。闭包允许我们封装构造函数并确保外部无法直接创建新实例。
const Singleton = (function () {
let instance;
function createInstance(arg) {
return { arg };
}
return {
getInstance: function (arg) {
if (!instance) {
instance = createInstance(arg);
}
return instance;
},
};
})();
// 使用
const instance1 = Singleton.getInstance("First Argument");
const instance2 = Singleton.getInstance("Second Argument");
console.log(instance1.arg); // 'First Argument'
console.log(instance2.arg); // 'First Argument'(实例不变)
console.log(instance1 === instance2); // true
2. 使用 TypeScript
class Singleton {
private static instance: Singleton;
private constructor(public arg: string) {}
public static getInstance(arg: string): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton(arg);
}
return Singleton.instance;
}
public getArg(): string {
return this.arg;
}
}
// 使用
const instance1 = Singleton.getInstance("First Argument");
const instance2 = Singleton.getInstance("Second Argument");
console.log(instance1.getArg()); // 'First Argument'
console.log(instance2.getArg()); // 'First Argument'(实例不变)
console.log(instance1 === instance2); // true
3. 使用 Proxy
实现单例模式
class Singleton {
name = "";
constructor(name) {
this.name = name;
}
sayHi() {
console.log("Hi " + this.name);
}
}
const SingletonProxy = new Proxy(Singleton, {
instance: null,
construct(target, args) {
if (!this.instance) {
this.instance = new target(...args);
}
return this.instance;
},
});
// 使用
const instance1 = new SingletonProxy("First Argument");
const instance2 = new SingletonProxy("Second Argument");
console.log(instance1); // 'First Argument'
console.log(instance2.getArg()); // 'First Argument'(实例不变)
console.log(instance1 === instance2); // true