三亚做网站服务,wordpress短链接关键字,手机网站建设价位,网址缩短生成链接享元模式是一种用于性能优化的模式。 核心是运用共享技术来有效支持大量细粒度的对象。 场景1:假设有个内衣工厂#xff0c;目前产品有50个男式内衣和50个女式内衣#xff0c;为了推销产品#xff0c;需要给这些产品生产一些塑料模特来穿上他们的内衣拍成广告。 来看一个例子…享元模式是一种用于性能优化的模式。核心是运用共享技术来有效支持大量细粒度的对象。场景1:假设有个内衣工厂目前产品有50个男式内衣和50个女式内衣为了推销产品需要给这些产品生产一些塑料模特来穿上他们的内衣拍成广告。来看一个例子不使用享元模式的情况下varModelfunction(sex,underwear){this.sexsex;this.underwearunderwear;}Model.prototype.takePhotofunction(){console.log(sex${this.sex}underwear${this.underwear});}for(vari1;i50;i){varmaleModelnewModel(male,underwear${i});maleModel.takePhoto();}for(varj1;j50;j){varfemaleModelnewModel(female,underwear${j});femaleModel.takePhoto();}要得到一张照片每次需要传入sex和uunderwear参数综上所述现在一共有50种男内衣和50种女内衣所以会产生100个对象如果将来生产10000种内衣那这个程序可能因为存在如此多对象已经提前崩溃。思考下如何优化这个场景虽然有100种内衣但很显然不需要50个男模特和50个女模特其实男女模特只需要各自有一个就行了他们可以分别穿上不同内衣来拍照。下面来改写下这个代码varModelfunction(sex,underwear){this.sexsex;// this.underwear underwear;}Model.prototype.takePhotofunction(){console.log(sex${this.sex}underwear${this.underwear});}varmaleModelnewModel(male);varfemaleModelnewModel(female);for(vari1;i50;i){maleModel.underwearunderwear${i}maleModel.takePhoto();}for(varj1;j50;j){femaleModel.underwearunderwear${j}femaleModel.takePhoto();}可以看到改进之后的代码只需要两个对象便完成了同样的功能。这个例子就是享元模式的雏形享元模式要求将对象的属性划分为内部状态和外部状态状态在这里通常指属性享元模式的目标是尽量减少共享对象的数量。内部状态存储于对象内部内部状态可以被一些对象共享。内部状态独立于具体的场景通常不会改变。外部状态取决于具体的场景并根据场景而变化外部状态不能被共享。在上面的例子中性别是内部状态内衣是外部状态通过区分这两种状态大大减少了系统中的对象数量通常来讲内部状态有多少种组合系统中便最多存在多少个对象因为性别通常只有男女所以该内衣厂商最多只需要2个对象。这样一来我们便可以把所有内部状态相同对象指定为同一个共享对象而外部状态可以从对象身上剥离出来并存储在外部。剥离了外部状态的对象成为共享对象外部状态在必要时被传入共享对象来组装成一个完整的对象虽然组装外部状态成为一个完整对象的过程需要花费一定事件但却可以大大减少系统中的对象数量相比之下这点时间或许是微不足道的。因此享元模式是一种用时间换空间的优化模式。下面看下这个例子varid0;window.startUploadfunction(uploadType,files){// uploadType是区分控件还是flashfor(vari0,file;filefiles[i];){varuploadObjnewUpload(uploadType,file.fileName,file.fileSize);uploadObj.init(id);// 给upload对象设置一个唯一的id}}varUploadfunction(uploadType,fileName,fileSize){this.uploadTypeuploadType;this.fileNamefileName;this.fileSizefileSize;this.domnull;}Upload.prototype.initfunction(id){varthatthis;this.idid;this.domdocument.createElement(div);this.dom.innerHTMLspan文件名称${this.fileName},文件大小${this.fileSize}/span button classdelFile删除/button;this.dom.querySelector(.delFile).onclickfunction(){that.delFile();}document.body.appendChild(this.dom);}Upload.prototype.delFilefunction(){if(this.fileSize3000){returnthis.dom.parentNode.removeChild(this.dom);}if(window.confirm(确定要删除该文件吗this.fileName)){returnthis.dom.parentNode.removeChild(this.dom);}}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,},]);这个代码是有多少需要上传的文件就一共创建了多少个upload对象接下来我们用享元模式重构他// 剥离外部状态varUploadfunction(uploadType,fileName,fileSize){this.uploadTypeuploadType;}Upload.prototype.delFilefunction(id){uploadManager.setExternalState(id,this);console.log(this)if(this.fileSize3000){returnthis.dom.parentNode.removeChild(this.dom);}if(window.confirm(确定要删除该文件吗this.fileName)){returnthis.dom.parentNode.removeChild(this.dom);}}// 工厂进行对象实例化如果某个内部状态对应的共享对象已经被创建过那么直接返回这个对象否则创建一个新对象varUploadFactory(function(){varcreateFlyWeightObjs{};return{create:function(uploadType){console.log(createFlyWeightObjs[uploadType],createFlyWeightObjs,uploadType)if(createFlyWeightObjs[uploadType]){returncreateFlyWeightObjs[uploadType];}returncreateFlyWeightObjs[uploadType]newUpload(uploadType);}}})();// 管理器封装外部状态varuploadManager(function(){varuploadDatabase{};return{add:function(id,uploadType,fileName,fileSize){varflyWeightObjUploadFactory.create(uploadType);vardomdocument.createElement(div);dom.innerHTMLspan文件名称${fileName},文件大小${fileSize}/span button classdelFile删除/button;dom.querySelector(.delFile).onclickfunction(){flyWeightObj.delFile(id);}document.body.appendChild(dom);uploadDatabase[id]{fileName:fileName,fileSize:fileSize,dom:dom,};returnflyWeightObj;},setExternalState:function(id,flyWeightObj){varuploadDatauploadDatabase[id];for(variinuploadData){flyWeightObj[i]uploadData[i];}}}})();// 然后是开始出发上传动作的startUpload函数varid0;window.startUploadfunction(uploadType,files){// uploadType是区分控件还是flashfor(vari0,file;filefiles[i];){varuploadObjuploadManager.add(id,uploadType,file.fileName,file.fileSize);}}// 测试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个upload对象而通过享元模式重构之后对象的数量减少为2更幸运的是就算现在同时上传2000个文件需要创建的upload对象数量依然为2。没有内部状态的享元在文件上传的例子中我们分别进行过插件调用和Flash调用即startUpload(‘plugin’,[])和startUpload(‘flash’,[]),导致程序中创建了内部状态不同的两个共享对象也许你会奇怪在文件上传程序里一般都会提前通过特性检测来选择一种上传方式如果浏览器支持插件就用插件如果不支持插件那就用flash上传那么什么情况下既需要插件上传又需要Flash上传呢实际上这个需求是存在的很多网盘都提供了极速上传控件与普通上传Flash两种模式如果极速上传不好使可能没有安装控件或者控件损坏用户还可以随时切换到普通上传模式这里确实需要同时存在两个不同的upload共享对象。但并不是每个网站都必须做的如此复杂很多小一些的网站就支持单一的上传方式假设我们是这个网站的开发中不需要考虑极速上传与普通上传之间的切换这意味着在之前的代码中作为内部状态的uploadType属性是可以删除的在继续使用享元模式的前提下构造函数Upload就变成了无参数的形式。varUploadfunction(){}其他属性如fileName、fileSize,dom依然可以作为外部状态保存在共享对象外部在uploadType作为内部状态的时候他可能为控件也可能为Flash,所以当时最多可以组合出两个共享对象。而现在已经没有了内部状态这意味着只需要唯一的一个共享对象。现在我们要改写创建享元对象的工厂代码如下varUploadFactory(function(){varuploadObj;return{create:function(){if(uploadObj){returnuploadObj;}returncuploadObjnewUpload();}}})();管理器部分的代码不需要改动还是负责剥离和组装外部状态可以看到当对象没有内部状态的时候生产共享对象的工厂实际上变成了一个单例工厂。虽然这时候的共享对象没有了内部状态的区分但还是有剥离外部状态的过程我们依然倾向于称之为享元模式。非原创来源javascript设计模式与开发实践 -曾探