享元模式与其他大部分模式不一样,是为解决性能问题而生。在一个存在大量相似对象的系统中,享元模式可以很好的解决性能问题。
定义
运用共享技术来有效支持大量细粒度的对象。
实现
思路:
存在大量对象时,把其中共同部分抽离出来,如果有相同的业务请求,直接返回内存中已有对象。
需区分内部状态和外部状态:
- 内部状态存储在享元对象内部,可以共享。
- 外部状态随环境改变,不可以共享。享元对象的外部状态由客户端保存,在被享元对象创建以后,在需要使用时,再传入享元对象内部。
例子:
// 抽象享元类
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()
})
使用场景
- 系统有大量相似对象。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
优缺点
优点:
- 大大减少对象的创建,降低系统的内存,使效率提高;
缺点:
- 享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
- 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。