设计模式-javascript实现【享元模式】

定义:享元模式是一种用于性能优化的模式,其核心是运用共享技术来有效支持大量细粒度的对象。享元模式
要求将对象的属性划分为内部状态与外部状态(通常指属性),其目标是尽量减少共享对象的数量。
内部状态和外部状态:

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

我们便可以把所有内部状态相同的对象都指定为同一个共享对象。而外部状态可以从对象身上剥离出来,并储存
在外部。

1. 享元模式的实现

// 共享类
class Upload {
  constructor(uploadType){
    this.uploadType = uploadType;
  }

  delFile(){
    // 通过外部管理器设置 对象的fileSize
    uploadManager.setExternalState(id, this);
    if(this.fileSize < 3000){
      return this.dom.parentNode.removeChild(this.dom);
    }
    if(window.confirm('确定要删除该文件吗?’ + this.fileName)){
      return this.dom.parentNode.removeChild(this.dom);
    }
  }
}

// 工厂函数创建并缓存对象
const uploadFactory = (function(){
  const createdFlyWeightObjs = {};
  return {
    create: function(uploadType){
      if(createdFlyWeightObjs[uploadType]){
        return createdFlyWeightObjs[uploadType];
      }
      return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
    }
  };
})();

const uploadManager = (function(){
  const uploadDatabase = {};
  return {
    add: function(id, uploadType, fileName, fileSize){
      const flyWeightObj = UploadFactory.create(uploadType);
      const dom = document.createElement('div');
      dom.innerHTML = '<span>文件名称:' + fileName + ', 文件大小: ' + fileSize + '</span>' +
                      '<button class="delFile">删除</button>';
      dom.querySelector('.delFile').onclick = function(){
        flyWeightObj.delFile(id);
      };
      dom.body.appendChild(dom);
      uploadDatabase[id] = { fileName, fileSize, dom };
      return flyWeightObj;
    },
    setExternalState: function(id, flyWeightObj){
      const uploadData = uploadDatabase[id];
      for(let key in uploadData){
        flyWeightObj[key] = uploadData[key];
      }
    }
  };
});

const startUpload = function(uploadType, files){
  let id = 0;
  for(let i = 0; i < files.length; i++){
    uploadManager.add(++id, uploadType, files[i].fileName, files[i].fileSize);
  }
}
startUpload('plugin', [
  {
    fileName: '1.txt',
    fileSize: 1000
  },
  {
    fileName: '2.html',
    fileSize: 3000
  },
  {
    fileName: '3.txt',
    fileSize: 5000
  }
]);
startUpload('flash', [
  {
    fileName: '4.txt',
    fileSize: 1000
  },
  {
    fileName: '5.html',
    fileSize: 3000
  },
  {
    fileName: '6.txt',
    fileSize: 5000
  }
]);

享元模式是一种很好的性能优化方案,但它也会带来一些复杂性的问题,享元模式带来的好处很大程度上取决于
如何使用以及何时使用,一般来说,以下情况发生时便可以使用享元模式。

  • 一个程序中使用了大量的相似对象
  • 由于使用了大量对象,造成很大的内存开销
  • 对象的大多数状态都可以变为外部状态
  • 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象

2. 对象池

对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池里获取。如果对象
池里没有空闲对象,则创建一个新的对象,当获取出的对象完成它的职责之后,再进入池子等待被下次获取。
对象池是另外一种性能优化方案,它跟享元模式有一些相似之处,但没有分离内部状态和外部状态这个过程。

function objectFollFactory = function(createObjFn){
  let objectPool = [];
  return {
    create: function(){
      return  objectPool.length === 0 ?  createObjFn.apply(this, arguments) : objectPool.shift();
    },
    recover: function(obj){
      objectPool.push(obj);
    }
  };
}

const iframeFactory = objectPoolFactory(function(){
  const iframe = document.createElement('iframe');
  document.body.appendChild(iframe);

  iframe.onload = function(){
    iframe.onload = null;
    iframeFactory.recover(iframe);
  }
});

const iframe1 = iframeFactory.create();
iframe1.src = 'http://badiu.com';
const iframe2 = iframeFactory.create();
iframe2.src = 'http://qq.com';
posted @ 2023-03-16 15:39  箫笛  阅读(52)  评论(0编辑  收藏  举报