JavaScript设计模式总结-享元模式

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

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

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

举例
1、男女模特试衣服
若为每个模特对象Model均设置性别sex,underwear两个属性,每次试衣均创建了一次对象,会导致过多的对象。
由享元模式优化后,Model对象仅sex一个属性,而underwear属性在需要的时候才进行赋值
const Model = function(sex) {
  this.sex = sex;
}
Model.prototype.takePhoto = function() {
  console.log('sex= ' + this.sex + 'underwear' + this.underwear);
}
const maleModel = new Model('male');
const femaleModel = new Model('female');
for(let i = 1; i <= 50; i++) {
  maleModel.underwear = 'underwear' + i;
  femaleModel.takePhoto();
}
for(let j = 1; j <= 50; j++) {
  femaleModel.underwear = 'underwear' + j;
  femaleModel.takePhoto();
}
 
2、文件上传
为优化前
let id = 0;
window.startUpload = function(uploadType, files) {
  for(let i = 0, file; file = files[i++];) {
    const uploadObj = new Upload(uploadType, file.fileName, file.fileSize);
    uploadObj.init(id++);
  }
}

const Upload = function(uploadType, fileName, fileSize) {
  this.uploadType = uploadType;
  this.fileName = fileName;
  this.fileSize = fileSize;
  this.dom = null;
}
Upload.prototype.init = function(id) {
  this.id = id;
  this.dom = document.createElement('div');
  ...创建上传成功的fileName和fileSize相关展示DOM、绑定删除事件delFile()、插入DOM
}
Upload.prototype.delFile = function() {
  ...删除DOM节点及对象
}

调用

startUpload('plugin', [
  {
    fileName: '1.txt',
    fileSize: 1000,
  },
  {
    fileName: '2.txt',
    fileSize: 3000,
  },
  {
    fileName: '3.txt',
    fileSize: 5000,
  },
]);
 
用享元模式优化后
const Upload = function(uploadType) {
  this.uploadType = uploadType;
}
Upload.prototype.delFile = function(id) {
  uploadManager.setExternalState(id, this);
  ...删除DOM
}
const UploadFactory = (function() {
  const createdFlyWeightObjs = {};
  return {
    create(uploadType) {
      if (createdFlyWeightObjs[uploadType]) {
        return createdFlyWeightObjs[uploadType];
      }
      return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
    }
  }
})();
const uploadManager = (function() {
  const uploadDatabase = {};
  return {
    add(id, uploadType, fileName, fileSize) {
      // 仅仅创建基本type
      const flyWeightObj = UploadFactory.create(uploadType);

      ...添加展示的DOM和相应的删除事件delFile()
      
      // 存放额外的属性,通过调用 setExternalState() 函数将以下属性赋值到flyWeightObj上
      uploadDatabase[id] = {
        fileName,
        fileSize,
        dom,
      };
      return flyWeightObj;
    },
    setExternalState(id, flyWeightObj) {
      const uploadData = uploadDatabase[id];
      for(const i in uploadData) {
        flyWeightObj[i] = uploadData[i];
      }
    },
  }
})();
// 开始出发上传动作的startUpload函数
let id = 0;
window.startUpload = function(uploadType, files) {
  for(let i = 0, file; file = files[i++];) {
    const uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);
  }
}
// 使用
startUpload('plugin', [
  {
    fileName: '1.txt',
    fileSize: 1000,
  },
  {
    fileName: '2.txt',
    fileSize: 3000,
  },
  {
    fileName: '3.txt',
    fileSize: 5000,
  },
]);
对象池示例
页面上要动态创建、删除DOM节点,可以将创建的DOM用完后存放在内存中,需要的时候直接拿出来,而不是再创建
const objectPoolFactory = function(createObjFn) {
  const objectPool = [];
  return {
    create() {
      const obj === objectPool.length ?
            createObjFn.apply(this, arguments) : objectPool.shift();
      return obj;
    }
    recover(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);
  }
  return iframe;
});

const iframe1 = iframeFactory.create();
iframe1.src = 'http://baidu.com';

const iframe2 = iframeFactory.create();
iframe2.src = 'http://QQ.com';

参考文献:

[1] 《JavaScript设计模式与开发时间》,曾探,中国工信出版集团.

猜你喜欢

转载自www.cnblogs.com/yijingzheng/p/10367101.html