学习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之with的使用(阿里云、淘宝使用代码分析)
Oct 11 Javascript
微信小程序(三):网络请求
Jan 13 Javascript
JavaScript实现提交模式窗口后刷新父窗口数据的方法
Jun 16 Javascript
详解微信小程序中的页面代码中的模板的封装
Oct 12 Javascript
js使用ajax传值给后台,后台返回字符串处理方法
Aug 08 Javascript
微信小程序中转义字符的处理方法
Mar 28 Javascript
详解es6新增数组方法简便了哪些操作
May 09 Javascript
使用webpack将ES6转化ES5的实现方法
Oct 13 Javascript
vue使用原生swiper代码实例
Feb 05 Javascript
解决vue项目中出现Invalid Host header的问题
Nov 17 Javascript
vue 使用 sortable 实现 el-table 拖拽排序功能
Dec 26 Vue.js
pnpm对npm及yarn降维打击详解
Aug 05 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
Joomla数据库操作之JFactory::getDBO用法
2016/05/05 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
2016/06/13 PHP
关于laravel后台模板laravel-admin select框的使用详解
2019/10/03 PHP
thinkphp框架使用JWTtoken的方法详解
2019/10/10 PHP
PHPUnit + Laravel单元测试常用技能
2019/11/06 PHP
Javascript 学习书 推荐
2009/06/13 Javascript
json-lib出现There is a cycle in the hierarchy解决办法
2010/02/24 Javascript
jquery中邮箱地址 URL网站地址正则验证实例代码
2013/09/15 Javascript
用jquery的方法制作一个简单的导航栏
2014/06/23 Javascript
Javascript中封装window.open解决不兼容问题
2014/09/28 Javascript
JavaScript中用字面量创建对象介绍
2014/12/31 Javascript
JavaScript中利用Array和Object实现Map的方法
2015/07/27 Javascript
学习JavaScript设计模式(代理模式)
2015/12/03 Javascript
jQuery实现的表头固定效果实例【附完整demo源码下载】
2016/08/01 Javascript
jQuery通过ajax快速批量提交表单数据
2016/10/25 Javascript
node跨域请求方法小结
2017/08/25 Javascript
vue 标签属性数据绑定和拼接的实现方法
2018/05/17 Javascript
Vue实现拖放排序功能的实例代码
2019/07/08 Javascript
JS实现滑动拼图验证功能完整示例
2020/03/29 Javascript
python字符串中的单双引
2017/02/16 Python
python 对字典按照value进行排序的方法
2019/05/09 Python
谈一谈基于python的面向对象编程基础
2019/05/21 Python
Pytorch技巧:DataLoader的collate_fn参数使用详解
2020/01/08 Python
python装饰器三种装饰模式的简单分析
2020/09/04 Python
详解Python中如何将数据存储为json格式的文件
2020/11/18 Python
HTML5自定义元素播放焦点图动画的实现
2019/09/25 HTML / CSS
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
爱淘宝:淘宝网购物分享平台
2017/04/28 全球购物
程序员经常用到的UNIX命令
2015/04/13 面试题
企业内部培训方案
2014/02/04 职场文书
感恩老师的演讲稿
2014/05/06 职场文书
初中学校军训方案
2014/05/09 职场文书
优秀员工推荐材料
2014/12/20 职场文书
2015大学迎新标语
2015/07/16 职场文书
主婚人致辞精选
2015/07/28 职场文书
人身损害赔偿协议书
2016/03/22 职场文书