学习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错误的解决方案
Aug 07 Javascript
jqgrid 表格数据导出实例
Nov 21 Javascript
jQuery中append()方法用法实例
Jan 08 Javascript
浅谈JavaScript字符串与数组
Jun 03 Javascript
jQuery.trim() 函数及trim()用法详解
Oct 26 Javascript
Jquery和BigFileUpload实现大文件上传及进度条显示
Jun 27 Javascript
a标签跳转到指定div,jquery添加和移除class属性的实现方法
Oct 10 Javascript
运用jQuery写的验证表单(实例讲解)
Jul 06 jQuery
深入理解js A*寻路算法原理与具体实现过程
Dec 13 Javascript
VUE搭建手机商城心得和遇到的坑
Feb 21 Javascript
如何自动化部署项目?折腾服务器之旅~
Apr 16 Javascript
js+cavans实现图片滑块验证
Sep 29 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自动生成印有用户信息的名片
2016/08/01 PHP
详解PHP PDO简单教程
2019/05/28 PHP
PHP中__set()实例用法和基础讲解
2019/07/23 PHP
replace()方法查找字符使用示例
2013/10/28 Javascript
javascript获取选中的文本的方法代码
2013/10/30 Javascript
js时钟翻牌效果实现代码分享
2020/07/31 Javascript
HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
2016/10/31 Javascript
详解AngularJS验证、过滤器、指令
2017/01/04 Javascript
js实现下拉菜单效果
2017/03/01 Javascript
详解vue-cli构建项目反向代理配置
2017/09/07 Javascript
浅谈vue自定义全局组件并通过全局方法 Vue.use() 使用该组件
2017/12/07 Javascript
JavaScript 日期时间选择器一些小结
2018/04/02 Javascript
js html实现计算器功能
2018/11/13 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
2019/09/15 Javascript
微信小程序实现加入购物车滑动轨迹
2020/11/18 Javascript
[05:07]DOTA2英雄梦之声_第14期_暗影恶魔
2014/06/20 DOTA
浅谈function(函数)中的动态参数
2017/04/30 Python
Python入门_浅谈字符串的分片与索引、字符串的方法
2017/05/16 Python
详解Python中的动态属性和特性
2018/04/07 Python
Python实现的个人所得税计算器示例
2018/06/01 Python
python使用xlrd模块读取xlsx文件中的ip方法
2019/01/11 Python
Python 实现加密过的PDF文件转WORD格式
2020/02/04 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
浅析Python面向对象编程
2020/07/10 Python
pycharm2020.2 配置使用的方法详解
2020/09/16 Python
canvas烟花特效锦集
2018/01/17 HTML / CSS
值得收藏的HTML5资源(学习html5的朋友可以收藏下)
2010/07/20 HTML / CSS
html5使用canvas绘制文字特效
2014/12/15 HTML / CSS
模具毕业生推荐信
2014/02/15 职场文书
生产车间标语
2014/06/11 职场文书
门卫岗位职责说明书
2014/08/18 职场文书
2015年教师自我评价范文
2015/03/04 职场文书
人事任命通知书
2015/04/21 职场文书
获奖感言范文
2015/07/31 职场文书
病房管理制度范本
2015/08/06 职场文书
如何书写授权委托书?
2019/06/25 职场文书