标签:
享元模式是一种用于性能优化的模式,享元模式的核心是运用共享技术来有效支持大量细粒度的对象
以文件上传为例,文件上传功能可以选择依照队列,一个一个的排队上传,也支持同时选择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对象
划分内部状态和外部状态的关键主要有以下几点
首先,需要确认插件类型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对象
对象池也是一种共享相关的技术,对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接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设计模式与开发实践》读书笔记之享元模式
标签:
原文地址:http://www.cnblogs.com/GongQi/p/4663078.html