學習JavaScript設計模式之享元模式
一、定義
享元(flyweight)模式是一種用于性能優(yōu)化的模式,核心是運用共享技術(shù)來有效支持大量細刻度的對象。
在JavaScript中,瀏覽器特別是移動端的瀏覽器分配的內(nèi)存并不算多,如何節(jié)省內(nèi)存就成了一個非常有意義的事情。
享元模式是一種用時間換空間的優(yōu)化模式
- 內(nèi)衣工廠有100種男士內(nèi)衣、100中女士內(nèi)衣,要求給每種內(nèi)衣拍照。如果不使用享元模式則需要200個塑料模特;使用享元模式,只需要男女各1個模特。
二、什么場景下使用享元模式?
(1)程序中使用大量的相似對象,造成很大的內(nèi)存開銷
(2)對象的大多數(shù)狀態(tài)都可以變?yōu)橥獠繝顟B(tài),剝離外部狀態(tài)之后,可以用相對較少的共享對象取代大量對象
三、如何應用享元模式?
第一種是應用在數(shù)據(jù)層上,主要是應用在內(nèi)存里大量相似的對象上;
第二種是應用在DOM層上,享元可以用在中央事件管理器上用來避免給父容器里的每個子元素都附加事件句柄。
享元模式要求將對象的屬性分為內(nèi)部狀態(tài)和外部狀態(tài)。
內(nèi)部狀態(tài)獨立于具體的場景,通常不會改變,可以被一些對象共享;
外部狀態(tài)取決于具體的場景,并根據(jù)場景而變化,外部狀態(tài)不能被共享。
享元模式中常出現(xiàn)工廠模式,F(xiàn)lyweight的內(nèi)部狀態(tài)是用來共享的,F(xiàn)lyweight factory負責維護一個Flyweight pool(模式池)來存放內(nèi)部狀態(tài)的對象。
缺點:對象數(shù)量少的情況,可能會增大系統(tǒng)的開銷,實現(xiàn)的復雜度較大!
四、示例:文件上傳
var Upload = function(uploadType) { this.uploadType = uploadType; } /* 刪除文件(內(nèi)部狀態(tài)) */ Upload.prototype.delFile = function(id) { uploadManger.setExternalState(id, this); // 把當前id對應的外部狀態(tài)都組裝到共享對象中 // 大于3000k提示 if(this.fileSize < 3000) { return this.dom.parentNode.removeChild(this.dom); } if(window.confirm("確定要刪除文件嗎?" + this.fileName)) { return this.dom.parentNode.removeChild(this.dom); } } /** 工廠對象實例化 * 如果某種內(nèi)部狀態(tài)的共享對象已經(jīng)被創(chuàng)建過,那么直接返回這個對象 * 否則,創(chuàng)建一個新的對象 */ var UploadFactory = (function() { var createdFlyWeightObjs = {}; return { create: function(uploadType) { if(createdFlyWeightObjs[uploadType]) { return createdFlyWeightObjs[uploadType]; } return createdFlyWeightObjs[uploadType] = new Upload(uploadType); } }; })(); /* 管理器封裝外部狀態(tài) */ 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]; } } }; })(); /*觸發(fā)上傳動作*/ 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)對象池,也是一種性能優(yōu)化方案,其跟享元模式有一些相似之處,但沒有分離內(nèi)部狀態(tài)和外部狀態(tài)的過程。
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程序設計有所幫助。
相關(guān)文章
@ResponseBody 和 @RequestBody 注解的區(qū)別
這篇文章主要介紹了@ResponseBody 和 @RequestBody 注解的區(qū)別的相關(guān)資料,需要的朋友可以參考下2017-03-03JavaScript 刪除或抽取字符串指定字符的方法(極為常用)
這篇文章主要給大家分享了極為常用的JavaScript 刪除或抽取字符串指定字符的所有方法,具有一定的參考價值,需要的小伙伴可以參考一下2021-12-12JS實現(xiàn)點擊復選框變更DIV顯示狀態(tài)的示例代碼
下面小編就為大家分享一篇JS實現(xiàn)點擊復選框變更DIV顯示狀態(tài)的示例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12