学习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 相关文章推荐
javascript下IE与FF兼容函数收集
Sep 17 Javascript
《JavaScript高级程序设计》阅读笔记(一) ECMAScript基础
Feb 27 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
Nov 25 Javascript
页面元素绑定jquery toggle后元素隐藏的解决方法
Mar 27 Javascript
基于jQuery实现文本框缩放以及上下移动功能
Nov 24 Javascript
Vue方法与事件处理器详解
Dec 01 Javascript
Vue 过渡(动画)transition组件案例详解
Jan 22 Javascript
webpack之devtool详解
Feb 10 Javascript
layer更改皮肤的实现方法
Sep 11 Javascript
解决layui调用自定义方法提示未定义的问题
Sep 14 Javascript
layui禁用侧边导航栏点击事件的解决方法
Sep 25 Javascript
Vue如何实现验证码输入交互
Dec 07 Vue.js
纯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
PHP删除特定数组内容并且重建数组索引的方法.
2011/03/25 PHP
php将字符串转换为数组实例讲解
2020/05/05 PHP
关于jQuery新的事件绑定机制on()的使用技巧
2013/04/26 Javascript
浅析LigerUi开发中谨慎载入common.css文件
2013/07/09 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
Javasipt:操作radio标签详解
2013/12/30 Javascript
nodejs分页类代码分享
2014/06/17 NodeJs
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
js获取微信版本号的方法
2015/05/12 Javascript
javascript中FOREACH数组方法使用示例
2016/03/01 Javascript
基于angularjs实现图片放大镜效果
2016/08/31 Javascript
jsonp跨域请求实现示例
2017/03/13 Javascript
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
2017/06/04 Javascript
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
2017/07/02 Javascript
JS动画定时器知识总结
2018/03/23 Javascript
超出JavaScript安全整数限制的数字计算BigInt详解
2018/06/24 Javascript
CKEditor4配置与开发详细中文说明文档
2018/10/08 Javascript
浅析TypeScript 命名空间
2020/03/19 Javascript
JQuery基于FormData异步提交数据文件
2020/09/01 jQuery
Python实现批量下载图片的方法
2015/07/08 Python
python+pyqt实现右下角弹出框
2017/10/26 Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
2018/02/08 Python
centos 安装python3.6环境并配置虚拟环境的详细教程
2018/02/22 Python
pandas 两列时间相减换算为秒的方法
2018/04/20 Python
关于Python3 lambda函数的深入浅出
2019/11/27 Python
Python分析微信好友性别比例和省份城市分布比例的方法示例【基于itchat模块】
2020/05/29 Python
Python函数参数定义及传递方式解析
2020/06/10 Python
基于Python实现2种反转链表方法代码实例
2020/07/06 Python
《开国大典》教学反思
2014/04/19 职场文书
口才训练演讲稿范文
2014/09/16 职场文书
万能检讨书开头与结尾怎么写
2015/02/17 职场文书
毕业设计致谢词
2015/05/14 职场文书
2015大学迎新晚会主持词
2015/07/16 职场文书
民事调解协议书
2016/03/21 职场文书
创业计划书之DIY自助厨房
2019/09/06 职场文书
Python调用腾讯API实现人脸身份证比对功能
2022/04/04 Python