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


Posted in Javascript onJanuary 18, 2016

一、定义

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

  • 内衣工厂有100种男士内衣、100中女士内衣,要求给每种内衣拍照。如果不使用享元模式则需要200个塑料模特;使用享元模式,只需要男女各1个模特。

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

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

三、如何应用享元模式?

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

享元模式要求将对象的属性分为内部状态外部状态
内部状态独立于具体的场景,通常不会改变,可以被一些对象共享;
外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享。

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

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

四、示例:文件上传

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 = "<span>文件名称:" + fileName + ",文件大小:" + fileSize +"</span>"
             + "<button class='delFile'>删除</button>";

      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, uploadType, 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',
    fileSize: 1000
  },{
    fileName: '5.txt',
    fileSize: 3000
  },{
    fileName: '6.txt',
    fileSize: 5000
  }
]);

五、补充

(1)直接改变形参Demo

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

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

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程序设计有所帮助。

Javascript 相关文章推荐
JQuery 1.4 中的Ajax问题
Jan 23 Javascript
遨游,飞飞,IE,空中网 浏览器无提示关闭方法
Jul 11 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
May 17 Javascript
js中符号转意问题示例探讨
Aug 19 Javascript
jquery简单实现鼠标经过导航条改变背景图
Dec 17 Javascript
Angular的自定义指令以及实例
Dec 26 Javascript
微信小程序 配置顶部导航条标题颜色的实现方法
Sep 20 Javascript
jfinal与bootstrap的登出实战详解
Nov 27 Javascript
解决在vue项目中,发版之后,背景图片报错,路径不对的问题
Mar 06 Javascript
vue-cli3.0配置及使用注意事项详解
Sep 05 Javascript
浅谈针对Vue相同路由不同参数的刷新问题
Sep 29 Javascript
JavaScript 装逼指南(js另类写法)
May 10 Javascript
纯JavaScript基于notie.js插件实现消息提示特效
Jan 18 #Javascript
学习JavaScript设计模式之责任链模式
Jan 18 #Javascript
深入学习jQuery Validate表单验证(二)
Jan 18 #Javascript
深入学习jQuery Validate表单验证
Jan 18 #Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
Jan 18 #Javascript
图片旋转、鼠标滚轮缩放、镜像、切换图片js代码
Dec 13 #Javascript
理解JavaScript中Promise的使用
Jan 18 #Javascript
You might like
typecho插件编写教程(三):保存配置
2015/05/28 PHP
PHP 9 大缓存技术总结
2015/09/17 PHP
教你在header中隐藏php的版本信息
2016/08/10 PHP
PHP实现QQ登录的开原理和实现过程
2018/02/04 PHP
MSN消息提示类
2006/09/05 Javascript
目前流行的JavaScript库的介绍及对比
2013/09/29 Javascript
一个CSS+jQuery实现的放大缩小动画效果
2014/02/19 Javascript
Extjs实现下拉菜单效果
2016/04/01 Javascript
bootstrap3使用bootstrap datetimepicker日期插件
2017/05/24 Javascript
微信小程序实现点击文字页面跳转功能【附源码下载】
2017/12/12 Javascript
vue调试工具vue-devtools安装及使用方法
2018/11/07 Javascript
浅谈Webpack多页应用HMR卡住问题
2019/04/24 Javascript
微信小程序保存图片到相册权限设置
2020/04/09 Javascript
Element Alert警告的具体使用方法
2020/07/27 Javascript
[56:29]Secret vs Optic 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:04]不如跳舞!DOTA2新英雄玛尔斯的欢乐日常
2019/03/11 DOTA
详细解读Python中的__init__()方法
2015/05/02 Python
多版本Python共存的配置方法
2017/05/22 Python
使用python将图片格式转换为ico格式的示例
2018/10/22 Python
用Python实现BP神经网络(附代码)
2019/07/10 Python
python实现人机五子棋
2020/03/25 Python
Python代码中如何读取键盘录入的值
2020/05/27 Python
详解H5本地储存Web Storage
2017/07/03 HTML / CSS
html5绘制时钟动画
2014/12/15 HTML / CSS
html2canvas生成清晰的图片实现打印的示例代码
2019/09/30 HTML / CSS
一家专门做特卖的网站:唯品会
2016/10/09 全球购物
应届大学生自荐信格式
2013/09/21 职场文书
工商局副局长个人对照检查材料
2014/09/25 职场文书
学院党的群众路线教育实践活动整改方案
2014/10/04 职场文书
工作失误检讨书
2015/01/26 职场文书
挂靠协议书
2015/01/27 职场文书
小学开学典礼新闻稿
2015/07/17 职场文书
2015年法律事务部工作总结
2015/07/27 职场文书
小学教师教学反思
2016/02/24 职场文书
经典人生语录分享:不畏将来,不念过去,笑对当下
2019/12/12 职场文书
Oracle锁表解决方法的详细记录
2022/06/05 Oracle