学习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 21 Javascript
一个基于jquery的文本框记数器
Sep 19 Javascript
解决checkbox的attr(checked)一直为undefined问题
Jun 16 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
Feb 19 Javascript
JavaScript实现解析INI文件内容的方法
Nov 17 Javascript
基于JS实现仿百度百家主页的轮播图效果
Mar 06 Javascript
JS实现电话号码的字母组合算法示例
Feb 26 Javascript
vue-router 起步步骤详解
Mar 26 Javascript
JS实现求字符串中出现最多次数的字符和次数示例
Jul 05 Javascript
JavaScript表格隔行变色和Tab标签页特效示例【附jQuery版】
Jul 11 jQuery
使用vue打包进行云服务器上传的问题
Mar 02 Javascript
如何利用JavaScript实现二叉搜索树
Apr 02 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实现生成code128条形码的方法详解
2017/07/19 PHP
ThinkPHP5.1表单令牌Token失效问题的解决
2019/03/22 PHP
基于JQuery模仿苹果桌面的Dock效果(初级版)
2012/10/15 Javascript
window.opener用法和用途实例介绍
2013/08/19 Javascript
js获取url参数值的两种方式
2013/09/10 Javascript
javascript 拷贝节点cloneNode()使用介绍
2014/04/03 Javascript
JavaScript获取表单enctype属性的方法
2015/04/02 Javascript
JS动画效果打开、关闭层的实现方法
2015/05/09 Javascript
浅谈javascript的分号的使用
2015/05/12 Javascript
jQuery实现移动端滑块拖动选择数字效果
2015/12/24 Javascript
jquery拖拽排序简单实现方法(效果增强版)
2016/02/16 Javascript
JavaScript入门系列之知识点总结
2016/03/24 Javascript
sencha ext js 6 快速入门(必看)
2016/06/01 Javascript
基于JavaScript实现自动更新倒计时效果
2016/12/19 Javascript
详解nodejs实现本地上传图片并预览功能(express4.0+)
2017/06/28 NodeJs
解决layer 关闭当前弹窗 关闭遮罩层 input值获取不到的问题
2019/09/25 Javascript
详解如何用OpenCV + Python 实现人脸识别
2017/10/20 Python
python实现Windows电脑定时关机
2018/06/20 Python
python实现逐个读取txt字符并修改
2018/12/24 Python
更新修改后的Python模块方法
2019/03/03 Python
python flask几分钟实现web服务的例子
2019/07/26 Python
win10下安装Anaconda的教程(python环境+jupyter_notebook)
2019/10/23 Python
PyQt5多线程防卡死和多窗口用法的实现
2020/09/15 Python
基于Python实现体育彩票选号器功能代码实例
2020/09/16 Python
使用tkinter实现三子棋游戏
2021/02/25 Python
香港时装购物网站:ZALORA香港
2017/04/23 全球购物
菲律宾最大的网上花店和礼品店:PhilFlower.com
2018/02/09 全球购物
ZWILLING双立人法国网上商店:德国刀具锅具厨具品牌
2019/08/28 全球购物
说说在weblogic中开发消息Bean时的persistent与non-persisten的差别
2013/04/07 面试题
综合实践活动方案
2014/02/14 职场文书
元旦联欢会感言
2014/03/04 职场文书
项目经理岗位职责
2015/01/31 职场文书
陈斌强事迹观后感
2015/06/17 职场文书
新员工入职感言范文!
2019/07/04 职场文书
pycharm2021激活码使用教程(永久激活亲测可用)
2021/03/30 Python
Redis缓存-序列化对象存储乱码问题的解决
2021/06/21 Redis