学习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 相关文章推荐
JS 时间显示效果代码
Aug 23 Javascript
菜鸟javascript基础资料整理2
Dec 06 Javascript
jQuery满屏焦点图左右滚动特效代码分享
Sep 07 Javascript
JavaScript中数组添加值和访问值常见问题
Feb 06 Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
May 05 Javascript
jQuery Validate插件实现表单验证
Aug 19 Javascript
利用Node.js对文件进行重命名
Mar 12 Javascript
node.js 抓取代理ip实例代码
Apr 30 Javascript
详解Vue2.x-directive的学习笔记
Jul 17 Javascript
vue实现的下拉框功能示例
Jan 29 Javascript
Vue中img的src是动态渲染时不显示的解决
Nov 14 Javascript
解决elementUI 切换tab后 el_table 固定列下方多了一条线问题
Jul 19 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
一篇不错的PHP基础学习笔记
2007/03/18 PHP
Array of country list in PHP with Zend Framework
2011/10/17 PHP
php 启动时报错的简单解决方法
2014/01/27 PHP
jquery json 实例代码
2010/12/02 Javascript
jquery实现多行文字图片滚动效果示例代码
2014/10/10 Javascript
jQuery实现购物车计算价格功能的方法
2015/03/25 Javascript
jquery实现适用于门户站的导航下拉菜单效果代码
2015/08/24 Javascript
JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件
2015/12/20 Javascript
在Linux系统中搭建Node.js开发环境的简单步骤讲解
2016/01/26 Javascript
利用JS判断字符串是否含有数字与特殊字符的方法小结
2016/11/25 Javascript
JavaScript无缝滚动效果的实例代码
2017/03/27 Javascript
anime.js 实现带有描边动画效果的复选框(推荐)
2017/12/24 Javascript
Vue中在新窗口打开页面及Vue-router的使用
2018/06/13 Javascript
详解如何使用webpack打包JS
2018/06/21 Javascript
koa上传excel文件并解析的实现方法
2018/08/09 Javascript
js微信分享接口调用详解
2019/07/23 Javascript
js实现无限瀑布流实例方法
2019/09/16 Javascript
[08:02]DOTA2牵红线 zhou神抱得美人归
2014/03/22 DOTA
[01:06]DOTA2小知识课堂 Ep.01 TP出门不要忘记帮队友灌瓶哦
2019/12/05 DOTA
[50:44]DOTA2-DPC中国联赛 正赛 SAG vs Dragon BO3 第二场 2月22日
2021/03/11 DOTA
Python使用zip合并相邻列表项的方法示例
2018/03/17 Python
python 使用poster模块进行http方式的文件传输到服务器的方法
2019/01/15 Python
pytorch实现建立自己的数据集(以mnist为例)
2020/01/18 Python
python zip()函数的使用示例
2020/09/23 Python
CSS3 对过渡(transition)进行调速以及延时
2020/10/21 HTML / CSS
国际奢侈品品牌童装购物网站:Designer Childrenswear
2019/05/08 全球购物
销售类求职信
2014/06/13 职场文书
2014教师党员自我评议总结
2014/09/19 职场文书
上诉状格式
2015/05/23 职场文书
2016学习依法治国心得体会
2016/01/15 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书
基于nginx实现上游服务器动态自动上下线无需reload的实现方法
2021/03/31 Servers
Pytorch数据读取之Dataset和DataLoader知识总结
2021/05/23 Python
sql注入教程之类型以及提交注入
2021/08/02 MySQL
Redis集群节点通信过程/原理流程分析
2022/03/18 Redis
Python实现数据的序列化操作详解
2022/07/07 Python