一、定義
享元(flyweight)模式是一種用於效能最佳化的模式,核心是運用共享技術來有效支援大量細刻度的物件。
在JavaScript中,瀏覽器特別是行動端的瀏覽器所分配的記憶體並不算多,如何節省記憶體就成了非常有意義的事情。
享元模式是一種用時間換空間的最佳化模式
二、什麼場景下使用享元模式?
(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程式設計有所幫助。