学习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 面向对象全新理练之数据的封装
Dec 03 Javascript
我遇到的参数传递中 双引号单引号嵌套问题
Feb 11 Javascript
基于jQuery的js分页代码
Jun 10 Javascript
用RadioButten或CheckBox实现div的显示与隐藏
Sep 21 Javascript
JavaScript 学习笔记之操作符
Jan 14 Javascript
JS实现状态栏跑马灯文字效果代码
Oct 24 Javascript
整理Javascript基础语法学习笔记
Nov 29 Javascript
10分钟掌握XML、JSON及其解析
Dec 06 Javascript
js通过classname来获取元素的方法
Nov 24 Javascript
jQuery开源组件BootstrapValidator使用详解
Jun 29 jQuery
JS使用数组实现的队列功能示例
Mar 04 Javascript
原生js实现点击轮播切换图片
Feb 11 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
SSI指令
2006/11/25 PHP
PHP 5.0对象模型深度探索之类的静态成员
2008/03/27 PHP
php连接Access数据库错误及解决方法
2013/06/20 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
2019/02/28 PHP
Jquery replace 字符替换实现代码
2010/12/02 Javascript
基于jquery ui的alert,confirm方案(支持换肤)
2015/04/03 Javascript
javascript Promise简单学习使用方法小结
2016/05/17 Javascript
非常实用的js验证框架实现源码 附原理方法
2016/06/08 Javascript
javascript简单进制转换实现方法
2016/11/24 Javascript
利用js+css+html实现固定table的列头不动
2016/12/08 Javascript
js实现悬浮窗效果(支持拖动)
2017/03/09 Javascript
Vue2.5通过json文件读取数据的方法
2018/02/27 Javascript
Fundebug支持监控微信小程序HTTP请求错误的方法
2019/02/21 Javascript
Vue的H5页面唤起支付宝支付功能
2019/04/18 Javascript
基于jQuery的时间戳与日期间的转化
2019/06/21 jQuery
javascript实现切割轮播效果
2019/11/28 Javascript
python实现的生成随机迷宫算法核心代码分享(含游戏完整代码)
2014/07/11 Python
在Python中利用Pandas库处理大数据的简单介绍
2015/04/07 Python
Python 解决中文写入Excel时抛异常的问题
2018/05/03 Python
Php多进程实现代码
2018/05/07 Python
python语言线程标准库threading.local解读总结
2019/11/10 Python
TensorFlow命名空间和TensorBoard图节点实例
2020/01/23 Python
Python版中国省市经纬度
2020/02/11 Python
python实现批量修改文件名
2020/03/23 Python
html5利用canvas绘画二级树形结构图的示例
2017/09/27 HTML / CSS
HTML5 visibilityState属性详细介绍和使用实例
2014/05/03 HTML / CSS
大学生社会实践评语
2014/04/25 职场文书
中学生英语演讲稿
2014/04/26 职场文书
学校花圃的标语
2014/06/18 职场文书
幼儿园见习报告
2014/10/30 职场文书
泰坦尼克号观后感
2015/06/04 职场文书
婚宴致辞
2015/07/28 职场文书
教师节主题班会方案
2015/08/17 职场文书
Pytorch使用shuffle打乱数据的操作
2021/05/20 Python
js不常见操作运算符总结
2021/11/20 Javascript
golang实现浏览器导出excel文件功能
2022/03/25 Golang