学习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模板技术
Apr 27 Javascript
jquery 常用操作整理 基础入门篇
Oct 14 Javascript
javascript编写实用的省市选择器
Feb 12 Javascript
jQuery DataTables插件自定义Ajax分页实例解析
Apr 28 Javascript
纯JS前端实现分页代码
Jun 21 Javascript
一种基于浏览器的自动小票机打印实现方案(js版)
Jul 26 Javascript
jQuery读取XML文件的方法示例
Feb 03 Javascript
JavaScript获取tr td 的三种方式全面总结(推荐)
Aug 15 Javascript
React如何利用相对于根目录进行引用组件详解
Oct 09 Javascript
基于vue2的canvas时钟倒计时组件步骤解析
Nov 05 Javascript
js实现一个简易计算器
Mar 30 Javascript
js实现九宫格布局效果
May 28 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
NOT NULL 和NULL
2007/01/15 PHP
js和php邮箱地址验证的实现方法
2014/01/09 PHP
php中函数前加&amp;符号的作用分解
2014/07/08 PHP
兼容多浏览器的字幕特效Marquee的通用js类
2008/07/20 Javascript
简单的Jquery遮罩层代码实例
2013/11/14 Javascript
angular.foreach 循环方法使用指南
2015/01/06 Javascript
Javascript控制input输入时间格式的方法
2015/01/28 Javascript
浅谈javascript语法和定时函数
2015/05/03 Javascript
JavaScript实现上下浮动的窗口效果代码
2015/10/12 Javascript
JavaScript对象数组的排序处理方法
2015/10/21 Javascript
javascript中的3种继承实现方法
2016/01/27 Javascript
jQuery+HTML5+CSS3制作支持响应式布局时间轴插件
2016/08/10 Javascript
原生JS实现循环Nodelist Dom列表的4种方式示例
2018/02/11 Javascript
解决mpvue + vuex 开发微信小程序vuex辅助函数mapState、mapGetters不可用问题
2018/08/03 Javascript
浅谈JavaScript 代码简洁之道
2019/01/09 Javascript
vue--vuex详解
2019/04/15 Javascript
微信小程序websocket实现即时聊天功能
2019/05/21 Javascript
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
Python入门学习之字符串与比较运算符
2015/10/12 Python
python读取oracle函数返回值
2016/07/18 Python
Python3.5迭代器与生成器用法实例分析
2019/04/30 Python
django框架创建应用操作示例
2019/09/26 Python
Numpy之将矩阵拉成向量的实例
2019/11/30 Python
Python MySQLdb 执行sql语句时的参数传递方式
2020/03/04 Python
HTML5 Canvas画线技巧——实现绘制一个像素宽的细线
2013/08/02 HTML / CSS
美国设计师精美珠宝购物网:Netaya
2016/08/28 全球购物
惠普新加坡官方商店:HP Singapore
2020/04/17 全球购物
进修护士自我鉴定
2013/10/14 职场文书
教育学专业实习生的自我鉴定
2013/11/26 职场文书
人事专员岗位职责范本
2014/03/04 职场文书
2014年重阳节老干部座谈会局领导发言稿
2014/09/25 职场文书
个人四风问题对照检查材料
2014/09/26 职场文书
2015年出纳个人工作总结
2015/04/02 职场文书
2016形势与政策学习心得体会
2016/01/12 职场文书
浅析python中特殊文件和特殊函数
2022/02/24 Python
微信告警的zabbix监控系统 监控整个NGINX集群
2022/04/18 Servers