设计模式-单例模式

51 阅读1分钟

定义

单例模式,是一种创建型设计模式,确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。

可以通过静态属性和私有构造函数来实现单例模式。

UML 图

typescript 实现

1. 创建单例(静态属性和私有构造方法方式)

class Singleton {
  private static instance: Singleton;

  // 私有构造函数,防止外部调用 new 创建实例
  private Constructor() {}
  
  // 公开的静态方法,用于获取单例实例
  public static getInstance(): Singleton {
    if(!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

2. 示例

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2);

通用实现

1. 通过注册表实现(javascript 本身并无 private 关键字的作用)

// 公共代码
export const SingletonFactory = (function() {
  const instances = new Map();
  return function<T>(Constructor: new(...args: any[]) => T, ...args: any[]): T {
    if(instances.has(Constructor)) {
      return instances.get(Constructor);
    }
    const instance = new Constructor(...args);
    instances.set(Constructor, instance);
    return instance;
  }
})();

// 私有代码,示例
class Hi {
  private readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
  hi: void {
    console.log(this.name);
  }
}
let hi1 = SingletonFactory(Hi, "wen");
let hi2 = SingletonFactory(Hi, "fly");
console.log(hi1 === hi2);

2. 通过类实现(硬编码实现 private 构造函数)

// 公共代码
export const Singleton = <T extends new (...args: any[]) => any>(Constructor: T) => {
  let instance: InstanceType<T>;
  return class extends Constructor {
    constructor(...args: any[]) {
      super(...args);
      if(!instance) {
        instance = this as InstanceType<T>;
      }
      return instance;
    }
    public static getInstance(...args: any[]): InstanceType<T> {
      if(!instance) {
        instance = new this(...args);
      }
      return instance;
    }
  }
}

// 私有代码,示例
class Hi {
  private readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
  hi: void {
    console.log(this.name);
  }
}

let SingletonHi = Singleton(Hi);
const singletonHi1 = new SingletonHi("wen");
const singletonHi2 = new SingletonHi("fly");
const singletonHi3 = SingletonHi.getInstance("fly");
console.log(singletonHi1 === singletonHi2);
console.log(singletonHi1 === singletonHi3);