typeScript 设计模式 之 单例模式 (一)

256 阅读2分钟

单例模式定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的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.