学习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 相关文章推荐
解读IE和firefox下JScript和HREF的执行顺序
Jan 12 Javascript
javascript重写alert方法的实例代码
Mar 29 Javascript
常用的JavaScript模板引擎介绍
Feb 28 Javascript
ECMAScript6中Map/WeakMap详解
Jun 12 Javascript
点击页面任何位置隐藏div的实现方法
Sep 05 Javascript
JS类的定义与使用方法深入探索
Nov 26 Javascript
完美实现js选项卡切换效果(二)
Mar 08 Javascript
jQuery实现判断上传图片类型和大小的方法示例
Apr 11 jQuery
vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单
Nov 29 Javascript
vue elementUI table 自定义表头和行合并的实例代码
May 22 Javascript
微信JSSDK实现打开摄像头拍照再将相片保存到服务器
Nov 15 Javascript
微信小程序 bindtap 传参的实例代码
Feb 21 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 图片上添加透明度渐变的效果
2009/06/29 PHP
PHP GD库生成图像的几个函数总结
2014/11/19 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
php静态文件生成类实例分析
2015/01/03 PHP
php计算指定目录下文件占用空间的方法
2015/03/13 PHP
如何在旧的PHP系统中使用PHP 5.3之后的库
2015/12/02 PHP
详解PHP的Yii框架的运行机制及其路由功能
2016/03/17 PHP
PHP微商城开源代码实例
2019/03/27 PHP
jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答
2011/11/10 Javascript
js中arguments,caller,callee,apply的用法小结
2014/01/28 Javascript
jquery禁止回车触发表单提交
2014/12/12 Javascript
js实现键盘Enter键提交表单的方法
2015/05/27 Javascript
jQuery仿写百度百科的目录树
2017/01/03 Javascript
js实现省份下拉菜单效果
2017/02/15 Javascript
js禁止浏览器页面后退功能的实例(推荐)
2017/09/01 Javascript
React中的refs的使用教程
2018/02/13 Javascript
详解使用vue-admin-template的优化历程
2018/05/20 Javascript
解决Vue+Element ui开发中碰到的IE问题
2018/09/03 Javascript
js实现搜索栏效果
2018/11/16 Javascript
element实现合并单元格通用方法
2019/11/13 Javascript
Python在groupby分组后提取指定位置记录方法
2018/04/20 Python
pygame游戏之旅 游戏中添加显示文字
2018/11/20 Python
解决Django生产环境无法加载静态文件问题的解决
2019/04/23 Python
python实现图片中文字分割效果
2019/07/22 Python
Python编程快速上手——Excel表格创建乘法表案例分析
2020/02/28 Python
python如何导入依赖包
2020/07/13 Python
南非最大的花卉和送礼服务:NetFlorist
2017/09/13 全球购物
关于Java finally的面试题
2016/04/27 面试题
党员公开承诺书范文
2014/03/25 职场文书
带病坚持工作事迹
2014/05/03 职场文书
四风问题自我剖析材料
2014/10/07 职场文书
2014年党建工作汇报材料
2014/10/27 职场文书
开学第一周总结
2015/07/16 职场文书
redis实现的四种常见限流策略
2021/06/18 Redis
Windows11插耳机没反应怎么办? win11耳机没声音的多种解决办法
2021/11/21 数码科技
云服务器部署 Web 项目的实现步骤
2022/06/28 Servers