学习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 相关文章推荐
使用onbeforeunload属性后的副作用
Mar 08 Javascript
javascript 设为首页与加入收藏兼容多浏览器代码
Jan 11 Javascript
jquery怎样实现ajax联动框(二)
Mar 08 Javascript
动态载入js提高网页打开速度的方法
Jul 04 Javascript
jquery实现类似淘宝星星评分功能实例
Sep 12 Javascript
原生JS实现LOADING效果
Mar 16 Javascript
探究Javascript模板引擎mustache.js使用方法
Jan 26 Javascript
Web前端开发之水印、图片验证码
Nov 27 Javascript
浅谈javascript中的数据类型转换
Dec 27 Javascript
基于Vue和Element-Ui搭建项目的方法
Sep 06 Javascript
vue实现文字加密功能
Sep 27 Javascript
Element Alert警告的具体使用方法
Jul 27 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的ob_start();控制您的浏览器cache!
2006/11/25 PHP
php 获取可变函数参数的函数
2009/08/26 PHP
php抓取https的内容的代码
2010/04/06 PHP
获取用户Ip地址通用方法与常见安全隐患(HTTP_X_FORWARDED_FOR)
2013/06/01 PHP
ubuntu下编译安装xcache for php5.3 的具体操作步骤
2013/06/18 PHP
简单实用的PHP防注入类实例
2014/12/05 PHP
微信支付PHP SDK ―― 公众号支付代码详解
2016/09/13 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
2018/04/20 PHP
用javascript实现给出的盒子的序列是否可连为一矩型
2007/08/30 Javascript
js保留小数点后几位的写法
2014/01/03 Javascript
使用原生js实现页面蒙灰(mask)效果示例代码
2014/06/20 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
jQuery实现DIV层收缩展开的方法
2015/02/27 Javascript
JavaScript中的条件判断语句使用详解
2015/06/03 Javascript
Vue中的ref作用详解(实现DOM的联动操作)
2017/08/21 Javascript
详解VUE 对element-ui中的ElTableColumn扩展
2018/03/28 Javascript
jQuery实现table表格checkbox全选的方法分析
2018/07/04 jQuery
教你如何用node连接redis的示例代码
2018/07/12 Javascript
javascript使用canvas实现饼状图效果
2020/09/08 Javascript
[00:35]TI7不朽珍藏III——寒冰飞龙不朽展示
2017/07/15 DOTA
[04:05]TI9战队采访 - Natus Vincere
2019/08/22 DOTA
Python中删除文件的程序代码
2011/03/13 Python
python十进制和二进制的转换方法(含浮点数)
2018/07/07 Python
详解Django配置优化方法
2019/11/18 Python
Python 解码Base64 得到码流格式文本实例
2020/01/09 Python
详细分析Python垃圾回收机制
2020/07/01 Python
Python 用__new__方法实现单例的操作
2020/12/11 Python
豪华床上用品、床单和浴室必需品:Peacock Alley
2019/09/04 全球购物
倡议书范文格式
2014/05/12 职场文书
大跃进口号
2014/06/16 职场文书
讲党性心得体会
2014/09/03 职场文书
中班下学期个人总结
2015/02/12 职场文书
朋友圈早安励志语录!
2019/07/08 职场文书
幽默口才训练经典句子(48句)
2019/08/19 职场文书
Python 如何安装Selenium
2021/05/06 Python
利用Python实现模拟登录知乎
2022/05/25 Python