单例模式定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象等。在JavaScript开发中,单例模式的用途同样非常广泛。
简单实现一个单例
让我们以 Logger 辅助库的例子。 来简单实现一个单例模式。
简单实现单例,其实比较简单。 就是通过一个临时变量来缓存,创建的类的实例。 当获取实例时,将之前缓存的实例对象直接返回。
class Logger {
protected static instance:Logger;
private id: number = 0;
constructor() {
this.id = Math.random() // 随机生成一个随机数,来验证 - 是一个实例
}
public getID(): number {
return this.id
}
public createInstance(): Logger {
if(!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
}
// test case;
const logger: Logger = Logger.createInstance();
const logger2: Logger = Logger.createInstance();
console.log(logger.getID() === logger2.getID()) // true
上面我们已经实现了一个简单的单例模式。
但是,这种实现也存在一定的问题,就是我们这样做,增加了这个类的“不透明性”,使用者须提前知道这是一个单例类,并通过createInstance 方法创建类的实例,才能保证,多次调用依然能保证,使用的是类的唯一实例。
假设,使用不知道这是个,单例类。 则会像常规创建类的实例一样, 通过 new Logger() 来创建实例。 这时候,多次调用则会创建多个类的实例。
透明性解决办法
class Logger {
protected static instance:Logger;
private id: number = 0;
private constructor() {
if (Logger.instance) {
throw new Error("Error - use Logger.createInstance()");
}
this.id = Math.random() // 随机生成一个随机数,来验证 - 是一个实例
}
public getID(): number {
return this.id
}
public static createInstance(): Logger {
if(!Logger.instance) return new Logger();
return Logger.instance;
}
}
// test case;
const logger: Logger = new Logger();
// get an error.
如上所示。 我们通过给构造函数增加可访问性来避免单例类(Logger)被当做常规类直接 new.