Skip to content

享元模式

初始享元模式

假设有一个内衣厂,目前产品有 20 种男士内衣和 50 种女士内衣,工程决定找模特穿上拍照,也许需要找 50 个男人和 50 个女人来进行拍照,代码如下:

js
class Model {
  constructor(sex, underwear) {
    this.sex = sex // 性别
    this.underwear = underwear // 内衣
  }
  takePhoto() {
    console.log(`性别:${this.sex},内衣:${this.underwear}`)
  }
}

for (let i = 0; i < 50; i++) {
  const model = new Model('男', i)
  model.takePhoto()
}

for (let i = 0; i < 50; i++) {
  const model = new Model('女', i)
  model.takePhoto()
}

// 打印日志省略

我们可见,上面直接创建出了 100 个对象,但是如果数量量更大,那么创建出了更多的对象,对于性能,是有巨大损伤的

但是换一种思路,其实我们只需要男人和女人各一个就完全可以实现,只要让他们穿上不同的内衣即可。那么代码如下:

js
class Model {
  constructor(sex, underwear) {
    this.sex = sex // 性别
  }
  takePhoto() {
    console.log(`性别:${this.sex},内衣:${this.underwear}`)
  }
}

const modelMan = new Model('男')
const modelFemale = new Model('女')

for (let i = 0; i < 50; i++) {
  modelMan.underwear = i
  modelMan.takePhoto()
}

for (let i = 0; i < 50; i++) {
  modelFemale.underwear = i
  modelFemale.takePhoto()
}

改进后的例子中,就只是创建了两个对象就解决了问题

内部状态和外部状态

  • 内部状态存储于对象内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体从场景,通常不会改变
  • 外部状态取决于具体场景,根据场景而变化,外部状态不能被共享

对象爆炸

下面例子中,是一个上传文件的例子,每上传一个文件都新建一个对象,如果对象过多,对于性能的损耗是极大的

js
class UpLoad {
  constructor(uploadType, fileName, fileSize) {
    this.uploadType = uploadType
    this.fileName = fileName
    this.fileSize = fileSize
  }
  // 初始化
  init() {
    this.dom = document.createElement('div')
    this.dom.innerHTML = `
          <span>文件名称:${this.fileName} 文件大小:${this.fileName}</span>
          <button class="delete">删除</button>
        `
    this.dom.querySelector('.delete').addEventListener(
      'click',
      () => {
        this.delFile()
      },
      false
    )
    document.body.appendChild(this.dom)
  }
  // 删除
  delFile() {
    if (this.fileSize < 3000) {
      return this.dom.parentNode.removeChild(this.dom)
    }
    if (window.confirm(`确定删除吗?${this.fileName}`)) {
      return this.dom.parentNode.removeChild(this.dom)
    }
  }
}

function startUpload(uploadType, files) {
  files.map((file, index) => {
    const upload = new UpLoad(uploadType, file.fileName, file.fileSize)
    upload.init()
  })
}

startUpload('plugin', [
  { fileName: '1.txt', fileSize: 1000 },
  { fileName: '2.txt', fileSize: 3000 },
  { fileName: '3.txt', fileSize: 5000 }
])

startUpload('plugin', [
  { fileName: '4.txt', fileSize: 1000 },
  { fileName: '5.txt', fileSize: 3000 },
  { fileName: '6.txt', fileSize: 5000 }
])

享元模式重构文件上传

上面例子中,要先明确的是 uploadType 其实是一个内部状态,再将外部状态抽离即可,代码如下: