享元模式
定义
享元:共享的单元的意思。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。
不可变对象,指的是一旦通过构造函数初始化完成之后,它的状态(对象的成员变量或者属性)就不会再被修改了。
所以,不可变对象不能暴露任何 set() 等修改内部状态的方法。
之所以要求享元是不可变对象,那是因为它会被多处代码共享使用,避免一处代码对享元进行了修改,影响到其他使用它的代码。
举个例子,有个服装店,现在男女服装各100套,店家想把这总共200套衣服都穿在模特身上拍照作为展品。我们既可以批量构造对象或就构建男女对象,如下:
// 方式一
let Model = function (gender, style) {
this.gender = gender
this.style = style
}
for (let i = 0; i < 100; i++) {
let maleModel = new Model('male', 'style' + i)
}
for (let i = 0; i < 100; i++) {
let femaleModel = new Model('female', 'style' + i)
}
// 方式二
let Model = function (gender) {
this.gender = gender
}
let maleModel = new Model('male')
let femaleModel = new Model('female')
for (let i = 0; i < 100; i++) {
maleModel.style = 'style' + i
}
for (let i = 0; i < 100; i++) {
maleModel.style = 'style' + i
}
方式二代码就用到了享元模式,先根据性别来分别构建2种对象,避免不必要的内存损耗。其实在这里性别就是一种内部状态,构建出来的享元对象是不可变对象。变化的仅仅是模特实例传什么样的衣服而已。
适用场景
享元模式可以说是一种很好的性能优化方案,但它也会带来一些复杂性的问题,从上面代码的比较可以看到,享元模式需要分别多维护一个maleModel对象和一个femaleModel对象,在大部分不必要使用享元模式的环境下,这些开销是可以避免的。
享元模式带来的好处很大程度上取决于如何使用以及何时使用,一般来说,以下情况发生时便可以使用享元模式:
- 程序中使用了大量的相似对象
- 由于使用了大量对象,造成很大的内存开销
- 对象的大多数状态都可以变为外部状态
- 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象