JavaScript设计模式_09_享元模式
享元模式属于一种性能优化模式。当前端需要创建大量的js对象时,可以考虑使用这种模式进行优化。尤其是移动端,对内存的占用要求比较高,所以,如何节省内存就变成了一件非常有意义的事情。
/** * pre:享元模式:一种性能优化模式 * 使用共享技术来有效支持大量细粒度的对象 */ //--------- 示例1 ----------- /* * 有一家内衣工厂,生产了50种男士内衣和50种女士内衣。为了推销产品,他们决定用塑料模特拍广告进行推广。 * 正常情况下,需要用50个男模特和50个女模特,分别为他们穿上一款内衣进行拍照。 * 为了减少创建模特的开销,我们这里使用享元模式,建立1个男模特和1个女模特。 * 以下是示例程序: */ var model = function(sex) { this.sex = sex; this.underwear = null; }; model.prototype.setUnderwear = function(underwear) { this.underwear = underwear; }; model.prototype.takePhoto = function() { console.log("this sex : " + this.sex + ",this underwear : " + this.underwear); }; var maleModel = new model("male"); for(var i = 1; i <= 50; i++) { maleModel.setUnderwear("underwear" + i); maleModel.takePhoto(); } var femaleModel = new model("female"); for(var i = 1; i <= 50; i++) { femaleModel.setUnderwear("underwear" + i); femaleModel.takePhoto(); } //---------- 示例2 ------------- /* * 有一个文件上传模块,同时支持多个文件上传,上传方式分为插件、和flash两种方式,并要求上传的文件具有删除功能。 * 我们为每一个上传文件创建一个upload对象,通过操作这个对象来实现删除的功能。 * 以下是示例程序: */ var id = 0; window.startUpload = function(uploadType, files) { for(var i = 0, a; a = files[i++];) { var uploadObj = new Upload(uploadType, a.fileName, a.fileSize); uploadObj.init(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 _self = 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() { _self.delFile(); }; document.body.appendChild(this.dom); }; Upload.prototype.delFile = function() { if(this.fileSize < 3000) { return this.dom.parentNode.removeChild(this.dom); } if(window.confirm("确定要删除文件" + this.fileName + "?")) { return this.dom.parentNode.removeChild(this.dom); } }; startUpload("plugin", [{ fileName: "1.txt", fileSize: 1000 }, { fileName: "2.html", fileSize: 3000 }, { fileName: "3.pdf", fileSize: 5000 }]) startUpload("flash", [{ fileName: "4.txt", fileSize: 1000 }, { fileName: "5.html", fileSize: 3000 }, { fileName: "6.pdf", fileSize: 5000 }]); //------------ 示例3 ---------------- /** * 为了减少对象的创建,我们使用享元模式,对以上代码进行重构。 * 示例如下: */ var id = 0; var Upload = function(uploadType) { this.uploadType = uploadType; }; Upload.prototype.delFile = function(id) { manager.setExternalState(id, this); if(this.fileSize < 3000) { return this.dom.parentNode.removeChild(this.dom); } if(window.confirm("确定要删除文件" + this.fileName + "?")) { return this.dom.parentNode.removeChild(this.dom); } }; var createUploadFactory = (function() { var objCache = {}; return function(uploadType) { if(objCache[uploadType]) { return objCache[uploadType]; } return objCache[uploadType] = new Upload(uploadType); } })(); var manager = (function() { var uploadCache = {}; var add = function(id, uploadType, fileName, fileSize) { var uploadObj = createUploadFactory(uploadType); var dom = document.createElement("div"); dom.innerHTML = "<span>文件名称:" + fileName + ",文件大小:" + fileSize + "</span>" + "<button class='delFile'>删除</button>"; dom.querySelector(".delFile").onclick = function() { uploadObj.delFile(id); }; document.body.appendChild(dom); uploadCache[id] = { fileName: fileName, fileSize: fileSize, dom: dom, id: id }; return uploadObj; }; var setExternalState = function(id, obj) { var uploadObj = uploadCache[id]; for(var i in uploadObj) { obj[i] = uploadObj[i]; } }; return { add: add, setExternalState: setExternalState } })(); window.startUpload = function(uploadType, files) { for(var i = 0, a; a = files[i++];) { manager.add(id++, uploadType, a.fileName, a.fileSize); } } startUpload("plugin", [{ fileName: "1.txt", fileSize: 1000 }, { fileName: "2.html", fileSize: 3000 }, { fileName: "3.pdf", fileSize: 5000 }]) startUpload("flash", [{ fileName: "4.txt", fileSize: 1000 }, { fileName: "5.html", fileSize: 3000 }, { fileName: "6.pdf", fileSize: 5000 }]); /** * 通过以上的例子,我们可以看出,享元模式把对象的属性进行了缓存,当我们真正需要操作对象的时候,再给对象赋值相应的属性,从而达到一种多态,减少对象创建的效果。
* 另外,需要注意的是,使用享元模式也带来了一些复杂性问题。比如上面的例子中我们需要维护factory和manager这两个对象,在大部分不需要使用享元模式的情况下,这个开销可以避免 * 。一般来说以下情况发生时可以使用享元模式:
* 1、一个程序中使用了大量相似的对象;
* 2、由于使用了大量对象,造成了内存开销过大;
* 3、对象大多数的状态可变为外部状态;
* 4、剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象。 */
作者:『Stinchan』
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。