1. 享元模式

享元模式是一种用于性能优化的模式,享元模式的核心是运用共享技术来有效支持大量细粒度的对象

1.1 传统的文件上传方法

以文件上传为例,文件上传功能可以选择依照队列,一个一个的排队上传,也支持同时选择2000个文件。
假如每一个文件都对应着一个JavaScript上传对象的创建,2000个文件就会同时创建2000个upload对象
假设这里的文件上传支持插件和flash两种

var id=0;
window.startUpload=function(uploadType,files){//uploadType区分是控件还是flash
for(var i=0,file;file=files[i++];){
var uploadObj=new Upload(uploadType,file.fileName,file.fileSize);
uploadObj.init(id++);//给upload对象设置一个唯一的id
}
}; var Upload=function(uploadType,fileName,fileSize){
this.uploadType=uploadType;
this.fileName=fileName;
this.fileSize=fileSize;
this.dom=null;
}; Upload.prototype.init=function(id){
var that=this;
this.id=id;
this.dom=document.createElement('div');
this.dom.innerHTML=
'<span>文件名称:'+this.fileName+',文件大小:'+this.fileSize+'</span>'
+'<button class="delFile">删除</button>';
this.dom.querySelector('.delFile').onclick=function(){
that.delFile();
};
document.body.appendChild(this.dom);
}; Upload.prototype.delFile=function(){
return this.dom.parentNode.removeChild(this.dom);
};

接下来分别创建3个插件上传对象和3个flash上传对象

startUpload('plugin',[
{
fileName:'1.txt',
fileSize:1000
},
{
fileName:'2.html',
fileSize:3000
},
{
fileName:'3.txt',
fileSize:5000
}
]); startUpload('flash',[
{
fileName:'4.txt',
fileSize:1000
},
{
fileName:'5.html',
fileSize:3000
},
{
fileName:'6.txt',
fileSize:5000
}
]);

这里一共有6个需要上传的文件,一共创建了6个upload对象

1.2 享元模式重构文件上传

划分内部状态和外部状态的关键主要有以下几点

  • 内部状态储存于对象内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体的场景,通常不会改变
  • 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享

首先,需要确认插件类型uploadType是内部状态
upload对象必须依赖uploadType属性才能工作,因为插件上传、flash上传各自调用的接口是完全不一样的
fileName和fileSize是根据场景而变化,每个文件的fileName和fileSize都不一样,fileName和fileSize没有办法被共享,它们是外部状态

剥离外部状态

var Upload=function(uploadType){
this.uploadType=uploadType;
};

Upload.prototype.init函数不再需要,upload对象初始化工作被放在后面定义的uploadManager.add函数里面
接下来只需要定义Upload.prototype.delFile函数

Upload.prototype.delFile=function(id){
uploadManager.setExternalState(id,this);
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);
}
}
})();

管理器封装外部状态
完善前面提到的uploadManager对象,它负责向UploadFactory提交创建对象的请求
并用uploadDatabase对象保存所有的upload对象的外部状态

var uploadManager=(function(){
var uploadDatabase={};
return {
add:function(id,uploadType,fileName,fileSize){
var flyWeightObj=UploadFactory.create(uploadType);
var dom=document.createElement('div');
dom.innerHTML=
'<span>文件名称:'+this.fileName+',文件大小:'+this.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];
}
}
}
})();

触发上传动作的startUpload函数

var id=0;
window.startUpload=function(uploadType,files){
for(var i=0,file;file=files[i++];){
var uploadObj=uploadManager.add(++id,uploadType,file.fileName,file.fileSize);
}
};

接下来分别创建3个插件上传对象和3个flash上传对象

startUpload('plugin',[
{
fileName:'1.txt',
fileSize:1000
},
{
fileName:'2.html',
fileSize:3000
},
{
fileName:'3.txt',
fileSize:5000
}
]); startUpload('flash',[
{
fileName:'4.txt',
fileSize:1000
},
{
fileName:'5.html',
fileSize:3000
},
{
fileName:'6.txt',
fileSize:5000
}
]);

这里一共有6个需要上传的文件,一共创建了2个upload对象
一个是插件类型的upload对象,一个是flash类型的upload对象

1.3 对象池技术

对象池也是一种共享相关的技术,对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池获取
如果此时对象池里没有空闲对象,则创建一个新的对象

通用对象池实现

var objectPoolFactory=function(createObjFn){
var objectPool=[];
return {
create:function(){
var obj=objectPool.length === 0 ?
createObjFn.apply(this,arguments):objectPool.shift();
return obj;
},
recover:function(obj){
objectPool.push(obj);
}
}
};

利用objectPoolFactory创建一个装载iframe的对象池

var iframeFactory=objectPoolFactory(function(){
var iframe=document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload=function(){
iframe.onload=null;
iframeFactory.recover(iframe);//加载完成后,回收节点
}
return iframe;
}); setTimeout(function(){
var iframe=iframeFactory.create();
iframe.src='http://www.qq.com';
},1000);

这里每隔1秒通过工厂方法创建一个iframe,但是采用上述对象池,始终只会生产一个iframe对象

《JavaScript设计模式与开发实践》读书笔记之享元模式的更多相关文章

  1. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  2. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

  3. Javascript设计模式与开发实践读书笔记(1-3章)

    第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用   多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...

  4. javascript设计模式与开发实践阅读笔记(8)——观察者模式

    发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...

  5. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  6. javascript设计模式与开发实践阅读笔记(6)——代理模式

    代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...

  7. javascript设计模式与开发实践阅读笔记(4)——单例模式

    定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...

  8. 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式

    第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...

  9. 《JavaScript设计模式与开发实践》笔记第一章

    第一章 面向对象的JavaScript 动态类型语言和鸭子类型 编程语言按照数据类型大体可以分为两类:静态类型语言.动态类型语言. 静态类型语言:在编译时便已确定变量的类型. 优点: 在编译时就能发现 ...

随机推荐

  1. boost.asio系列——io_service

    IO模型 io_service对象是asio框架中的调度器,所有异步io事件都是通过它来分发处理的(io对象的构造函数中都需要传入一个io_service对象). asio::io_service i ...

  2. 工信部表态支持Linux,可是Linux又是什么呢?

    近日,工信部高层官员出面表态:工信部大力支持发展国产Linux操作系统,可是,Linux又是什么呢?假设依照工信部的说法,发展所谓"国产Linux".恐怕要给国家带来麻烦. 大家知 ...

  3. REPLACE...IN.....WITH.... 的使用

    REPLACE...IN.....WITH....   的使用,例子用于改变alv的gt_fieldcat_alv LOOP AT gt_fieldcat_alv ASSIGNING <fs_f ...

  4. Processing_百度百科

    Processing_百度百科 Processing

  5. MySQL内存表(MEMORY)说明 | 一个PHP程序员的备忘录

    MySQL内存表(MEMORY)说明 | 一个PHP程序员的备忘录 MySQL内存表(MEMORY)说明

  6. 精讚部落::MySQL 的MEMORY engine

    精讚部落::MySQL 的MEMORY engine MySQL 的MEMORY engine 無次要群組

  7. HTML属性

  8. 使用URLConnection提交请求

    URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和URL之间的通信连接.程序可以通过URLConnection实例向该URL发送请求,读取URL ...

  9. jQuery遍历函数

    jQuery遍历函数包含了用于筛选.查找和串联元素的方法. .add():将元素加入到匹配元素的集合中. .andSelf():把堆栈中之前的元素集加入到当前集合中. .children():获得匹配 ...

  10. [Android学习笔记]ListView中含有Button导致无法响应onItemClick回调的解决办法

    转自:http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html 问题描述: 当ListView的Item中的控件只是一些展示类 ...