This website requires JavaScript.

设计模式在 TypeScript 中的应用 - 享元模式

2018.01.07 17:28字数 1589阅读 590喜欢 5评论 5

享元模式与其他大部分模式不一样,是为解决性能问题而生。在一个存在大量相似对象的系统中,享元模式可以很好的解决性能问题。

定义

运用共享技术来有效支持大量细粒度的对象。

实现

思路:

  • 存在大量对象时,把其中共同部分抽离出来,如果有相同的业务请求,直接返回内存中已有对象。

  • 需区分内部状态和外部状态:

    • 内部状态存储在享元对象内部,可以共享。
    • 外部状态随环境改变,不可以共享。享元对象的外部状态由客户端保存,在被享元对象创建以后,在需要使用时,再传入享元对象内部。

例子:

// 抽象享元类
abstract class Shape {
  public abstract draw (): void
}

// 具体享元类
class Circle extends Shape {
  // color 为内部状态(属性)
  private color: string

  // radius 为外部状态(属性)
  private radius: number

  // 内部状态不会随环境改变
  public constructor (color: string) {
    super()
    this.color = color
  }

  // 外部状态在需要时,在传入对象内部
  public setRadius (radius: number): void {
    this.radius = radius
  }

  public draw () {
    console.log(`Circle draw: color(${this.color}), radius(${this.radius})`)
  }
}

// 享元工厂类,生成基于给定信息的实体类的对象
class CircleFactory {

  // 创建缓存,键值为颜色值,
  private static cache: Map<string, Circle> = new Map()

  // 当收到创建特定颜色对象的请求时,先检查缓存中是否存在
  // 若存在,直接返回对象
  // 不存在时,才创建新对象,并加入到缓存
  public static getCircle (color: string): Circle {
    let circle = this.cache.get(color)
    if (!circle) {
      console.log(`created new Circle!`)
      circle = new Circle(color)
      this.cache.set(color, circle)
    }
    return circle
  }
}

let colors = [ 'Red', 'Green', 'Blue', 'Red', 'Green' ]
colors.forEach(color => {
  let circle = CircleFactory.getCircle(color)
  circle.setRadius(100)
  circle.draw()
})

使用场景

  • 系统有大量相似对象。
  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

优缺点

优点:

  • 大大减少对象的创建,降低系统的内存,使效率提高;

缺点:

  • 享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
  • 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。