设计模式-享元模式

25 阅读1分钟

定义

享元模式,是一种结构型涉及模式,它通过共享尽可能多的相似对象来减少内存,特别使用于大量对象几乎相同的情况。

它通过将对象的状态分为内部状态和外部状态来实现共享。

UML 类图

typescript 实现

1. 创建享元类

class Flyweight {
  private intrinsicState: string;
  constructor(intrinsicState: string) {
    this.intrinsicState = intrinsicState;
  }
  public operation(extrinsicState: string): void {
    console.log(`Flyweight: Intrinsic State - ${this.intrinsicState}, Extrinsic State - ${extrinsicState}`);
  }
}

2. 创建享元工厂

class FlyweightFactory {
  private flyweights: {[key: string]: Flyweight} = {};
  
  constructor(initialFlyweights: string[]) {
    for(const state of initialFlyweights) {
      this.flyweights[state] = new Flyweight(state);
    }
  }
  public getFlyweight(intrinsicState: string): Flyweight {
    if (!(intrinsicState in this.flyweights)) {
      console.log('FlyweightFactory: Cannot find a flyweight, creating new one.');
      this.flyweights[intrinsicState] = new Flyweight(intrinsicState);
    } else {
      console.log('FlyweightFactory: Reusing existing flyweight.');
    }
      return this.flyweights[intrinsicState];
  }
  public listFlyweights(): void {
    const count = Object.keys(this.flyweights).length;
    console.log(`FlyweightFactory: I have ${count} flyweights`);
    for(const key in this.flyweights) {
      console.log(key);
    }
  }
}

3. 使用示例

const factory = new FlyweightFactory(['state1', 'state2', 'state3']);
factory.listFlyweights();

通用实现

1. 工厂函数方式

// 公共代码
export const FlyweightFactory = (function() {
  const instances = new Map<string, any>();
  function getMapKey(Constructor: Function, args: any[]): string {
    return Constructor.name + JSON.stringify(args);
  }
  return {
    getFlyweight<T>(Constructor: new(...args: any[]) => T, args: any[]): T {
      const key = getMapKey(Constructor, args);
      if(instances.has(key)) {
        return instances.get(key);
      } else {
        const instance = new Constructor(...args);
        instances.set(key, instance);
        return instance;
      }
    },
    removeFlyweight<T>(Constructor: new(...args: any[]) => T, args: any[]): void {
      const key = getMapKey(Constructor, args);
      if(instances.has(key)) {
        instances.delete(key);
      }
    },
    listFlyweights(): void {
      for(let [key, value] of instances.entries()) {
        console.log(`Key: ${key}, Instance: ${value}`);
      }
    }
  }
})();

// 私有代码,使用示例
class Hi {
  prvaite name: string;
  constructor(name: string) {
    this.name = name;
  }
}
const hi1 = FlyweightFactory.getFlyweight(Hi, ["wenix"]);
const hi2 = FlyweightFactory.getFlyweight(Hi, ["wenix2"]);
console.log(hi1 === hi2);

2. 类方式

// 公共代码
export class Flyweight<T> {
  private readonly Constructor: { new(...args: any[]): T };
  private instances = new Map<string, T>();
  
  constructor(Constructor: new (...args: any[]) => T) {
    this.Constructor = Constructor;
  }
  public getFlyweight(args: any[]): T {
    const key = JSON.stringify(args);
    let instance = this.instances.get(key);
    if(!instance) {
      instance = new this.Constructor(...args);
      this.instances.set(key, instance);
    }
    return instance;
  }
  public removeFlyweight(args: any[]): void {
    const key = JSON.stringify(args);
    if(this.instances.has(key)) {
      this.instances.delete(key);
    }
  }
  public listFlyweight() {
    for(let [key, value] of this.instances.entries()) {
      console.log(`Key: ${key}, Instance: ${value});
    }
  }
}

// 私有代码,使用示例
class Hi {
  private name: string;
  constructor(name: string) {
    this.name = name;
  }
}
const HiFlyweight = new Flyweight(Hi);
const hi1 = HiFlyweight.getFlyweight(["wenix"]);
const hi2 = HiFlyweight.getFlyweight(["wenix2"]);
console.log(hi1 === hi2);