学习JavaScript设计模式之享元模式

一、定义

享元(flyweight)模式是一种用于性能优化的模式,核心是运用共享技术来有效支持大量细刻度的对象。 在JavaScript中,浏览器特别是移动端的浏览器分配的内存并不算多,如何节省内存就成了一个非常有意义的事情。 享元模式是一种用时间换空间的优化模式

二、什么场景下使用享元模式?

(1)程序中使用大量的相似对象,造成很大的内存开销 (2)对象的大多数状态都可以变为外部状态,剥离外部状态之后,可以用相对较少的共享对象取代大量对象

三、如何应用享元模式?

第一种是应用在数据层上,主要是应用在内存里大量相似的对象上; 第二种是应用在DOM层上,享元可以用在中央事件管理器上用来避免给父容器里的每个子元素都附加事件句柄。

享元模式要求将对象的属性分为

内部状态

外部状态

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

享元模式中常出现工厂模式,Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(模式池)来存放内部状态的对象。

缺点:对象数量少的情况,可能会增大系统的开销,实现的复杂度较大!

四、示例:文件上传

rush:js;"> var Upload = function(uploadType) { this.uploadType = uploadType; }

/ 删除文件(内部状态) /
Upload.prototype.delFile = function(id) {
uploadmanger.setExternalState(id,this); // 把当前id对应的外部状态都组装到共享对象中
// 大于3000k提示
if(this.fileSize < 3000) {
return this.dom.parentNode.removeChild(this.dom);
}
if(window.confirm("确定要删除文件吗?" + this.fileName)) {
return this.dom.parentNode.removeChild(this.dom);
}
}

/** 工厂对象实例化

  • 如果某种内部状态的共享对象已经被创建过,那么直接返回这个对象
  • 否则,创建一个新的对象
    */
    var UploadFactory = (function() {
    var createdFlyWeightObjs = {};
    return {
    create: function(uploadType) {
    if(createdFlyWeightObjs[uploadType]) {
    return createdFlyWeightObjs[uploadType];
    }
    return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
    }
    };
    })();

/ 管理器封装外部状态 /
var uploadmanger = (function() {
var uploadDatabase = {};

return {
add: function(id,uploadType,fileName,fileSize) {
var flyWeightObj = UploadFactory.create(uploadType);
var dom = document.createElement('div');
dom.innerHTML = "文件名称:" + fileName + ",文件大小:" + fileSize +""

  dom.querySelector(".delFile").onclick = function() {
    flyWeightObj.delFile(id);
  };
  document.body.appendChild(dom);

  uploadDatabase[id] = {
    fileName: fileName,fileSize: fileSize,dom: dom
  };

  return flyWeightObj;
},setExternalState: function(id,flyWeightObj) {
  var uploadData = uploadDatabase[id];
  for(var i in uploadData) {
    // 直接改变形参(新思路!!)
    flyWeightObj[i] = uploadData[i];
  }
}

};
})();

/触发上传动作/
var id = 0;
window.startUpload = function(uploadType,files) {
for(var i=0,file; file = files[i++];) {
var uploadobj = uploadmanger.add(++id,file.fileName,file.fileSize);
}
};

/ 测试 /
startUpload("plugin",[
{
fileName: '1.txt',fileSize: 1000
},{
fileName: '2.txt',fileSize: 3000
},{
fileName: '3.txt',fileSize: 5000
}
]);
startUpload("flash",[
{
fileName: '4.txt',{
fileName: '5.txt',{
fileName: '6.txt',fileSize: 5000
}
]);

五、补充

(1)直接改变形参Demo

rush:js;"> function f1() { var obj = {a: 1}; f2(obj); console.log(obj); // {a: 1,b: 2} } function f2(obj) { obj.b = 2; } f1();

(2)对象池,也是一种性能优化方案,其跟享元模式有一些相似之处,但没有分离内部状态和外部状态的过程。

rush:js;"> var objectPoolFactory = function(createObjFn) { var objectPool = []; return { create: function() { var obj = objectPool.lenght === 0 ? createObjFn.apply(this,arguments) : objectPool.shift(); return obj; },recover: function() { objectPool.push(obj); } }; }

希望本文所述对大家学习javascript程序设计有所帮助。

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...