目標
通過儘量減少共享對象的數量,運用共享技術來有效支持大量細粒度的對象。
要點
- 享元模式是一種用時間換空間的性能優化模式。
- 享元模式要求將對象的屬性劃分為內部狀態和外部狀態,所有內部狀態相同的對象都指定為同一個共享的對象,外部狀態在必要時被傳入共享對象來組裝成一個完整的對象。
- 劃分內部狀態和外部狀態的關鍵在於:內部狀態存儲於對象內部;內部狀態獨立於具體的場景,通常不會改變。
- 有多少種內部狀態的組合,系統中便最多存在多少個共享對象。
- 享元模式的適用場景:程序中使用了大量的對象;使用的大量對象造成了很大的內開銷;對象的大多數狀態可以變為外部狀態;剝離出對象的外部狀態之後,可以用相對較少的共享對象取代大量對象。
- 沒有內部狀態的享元模式只需要唯一的一個共享對象,生產共享對象的工廠實際上變成了一個單例工廠。但因為有剝離外部狀態的過程,所以它還是屬於享元模式。
- 對象池:另一種和享元模式相似的性能優化方案,但沒有分離內部狀態和外部狀態的過程。
核心代碼
var Upload = function(uploadType) {
this.uploadType = uploadType;
};
var UploadFactory = (function() {
var createdFlyWeightObjs = {};
return {
create: function(uploadType) {
if (createdFlyWeightObjs[uploadType]) {
return createdFlyWeightObjs[uploadType];
} else {
return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
}
}
};
})();
var uploadManager = (function() {
var uploadDatabase = {};
return {
add: function(id, uploadType, otherParams) {
var flyWeightObj = UploadFactory.create(uploadType);
// 結合外部狀態進行操作
// ...
uploadDatabase[id] = {
// 記錄 id 號的對象對應的外部狀態
// ...
};
return flyWeightObj;
},
setExternalState: function(id, flyWeightObj) {
var uploadData = uploadDatabase[id];
for (var i in uploadData) {
flyWeightObj[i] = uploadData[i];
}
}
};
})();
\\ 通用對象池的實現
var objectPoolFactory = function(createObjFn) {
var objectPool = [];
return {
create: function() {
var obj = objectPool.length ? objectPool.shift() : createObjFn.apply(this, arguments);
return obj;
},
recover: function(obj) {
objectPool.push(obj);
}
};
};
var iframeFactory = objectPoolFactory(function() {
var iframe = document.createElement('iframe');
// ...
iframe.onload = function() {
iframe.onload = null;
iframeFactory.recover(iframe); // iframe 加載完成之後回收
};
return iframe;
});
var iframe1 = iframeFactory.create();
iframe1.src = 'http://baidu.com';
setTimeout(function() {
var iframe2 = iframeFactory().create();
iframe2.src = 'http://qq.com';
}, 30000);