luoxue-victor / my-blog

公众号【前端技匠】作者

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

专题6: 设计模式之享元模式

luoxue-victor opened this issue · comments

模式定义

享元模式,运用共享技术,有效地支持大量的细粒度的对象,以避免对象之间拥有相同内容而造成多余的性能开销。

享元(flyweight)模式的主要作用:性能优化,当系统创建过多相似的对象而导致内存占用过高,可以采用这种设计模式进行优化。

享元模式将对象的属性区分为内部状态与外部状态,内部状态在创建的时候赋值,外部状态在实际需要用到的时候进行动态赋值

对于内部状态和外部状态的区分,有几点:

  1. 内部状态存储于对象内部
  2. 内部状态可以被一些对象共享
  3. 内部状态独立于具体场景,通常不会改变
  4. 外部状态取决于具体场景,并根据场景变化,外部状态不能被共享。

实战

我们要创建 100 个大小相同颜色不同的 div。

不使用享元模式的做法是:

  1. 创建一个创建 div 的类,CreateDiv。
  2. new CreateDiv() 创建 div
  3. 我们需要 new 100 次。这样就造成了很大的空间浪费。
interface Div {
  width: number;
  height: number;
  color: string;
}
const divStore: Div[] = [];

class CreateDiv {
  public width = 100;
  public height = 100;
  public color = this.randomColor()
  // 随机颜色
  private randomColor () {
    const color = ['red', 'green', 'blue', 'white', 'black'];
    return color[Math.floor(Math.random() * color.length)];
  }
}

let count = 100;
while (count--) {
  const innerDiv = new CreateDiv();
  divStore.push(innerDiv);
}

const sizeof = require('object-sizeof')

console.log(sizeof(divStore)) // 5688

享元模式来做

// 将 div 属性设置成内部跟外部两部分
interface Div {
  outer: {
    width: number;
    height: number;
  };
  innter: {
    color: string;
  };
}
// 用来储存 Div
const divStore: Div[] = [];
// 创建外部 div 类
class CreateOuterDiv {
  width: number = 100;
  height: number = 100;
}
class CreateInnerDiv {
  public color = this.randomColor()
  // 随机颜色
  private randomColor () {
    const color = ['red', 'green', 'blue', 'white', 'black'];
    return color[Math.floor(Math.random() * color.length)];
  }
}
// 创建外部 div
const outerDiv = new CreateOuterDiv();
let innerDiv: number;
let count = 100;

while (count--) {
  // 创建内部 div
  innerDiv = new CreateInnerDiv();
  divStore.push({
    outer: outerDiv,
    innter: innerDiv
  });
}

const sizeof = require('object-sizeof')
// 因为这个方法会把引用的对象也全部算一遍,所以我们拆开来算

// 验证:100 * (innerDiv + outerDiv)= 5400 与上面算的 5688 很接近,可以认为这个方法是准确的
console.log(100 * (sizeof(innerDiv) + sizeof(outerDiv))) // 5400
// 100 * innerDiv + outerDiv = 1638
console.log(100 * sizeof(innerDiv) + sizeof(outerDiv)) // 1638

从上面的计算结果来看减少了很大的内存,因为 divStore 数组对象中 outerDiv 其实只有一个,都是它的引用而已。我们的内存占用是 100 * innerDiv + outerDiv,而不使用享元模式的空间是 100 * (innerDiv + outerDiv)