JS设计模式笔记(享元模式)
享元模式
享元模式是一种用于性能优化的模式
内部状态与外部状态
享元模式要求将对象的属性划分为内部状态和外部状态(状态在这里通常指属性);
- 内部状态存储于对象内部
- 内部状态可以被一些对象共享
- 内部状态独立于具体的场景,通常不会改变
- 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享
文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| var Upload = function(uploadType) { this.uploadType = uploadType; };
Upload.prototype.delFile = function(id) { uploadManager.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 UploadFactory = (function() { var createdFlyWeightObjs = {};
return { create: function(uploadType) { if (createdFlyWeightObjs[uploadType]) { return createdFlyWeightObjs[uploadType]; }
return createdFlyWeightObjs[uploadType] = new Upload(uploadType); } } }());
var uploadManager = (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 = uploadManager.add(++id, uploadType, file.fileName, file.fileSize); } };
startUpload('plugin', [{ fileName: '1.txt', fileSize: 1000 },{ fileName: '2.html', fileSize: 3000 }]);
startUpload('flash', [{ fileName: '4.txt', fileSize: 1000 }, { fileName: '5.html', fileSize: 3000 }]);
|
效果
享元模式的适用性
- 一个程序中使用了大量相似的对象
- 由于使用了大量对象,造成了很大的内存开销
- 对象的大多数状态都可以变成外部状态
- 剥离对象的外部状态之后,可以使用相对较少的共享对象取代大量对象
- 有多少种内部状态的组合,系统中国便存在多少个共享对象
对象池
享元模式的过程是剥离外部状态,并把外部状态保存到其它地方,在合适的时刻再把外部状态组装进共享对象
对象池维护一个装载空闲对象的池子,如果需要对象时,不是直接new,而是转从对象池里获取;对象池没有分离外部状态和内部状态这个过程
iframe加载-对象池实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| var objectPoolFactory = function(createObjFn) { var objPool = [];
return { create: function() { console.log(objPool.length); return (objPool.length === 0 ? createObjFn.apply(this, arguments) : objPool.shift()); }, revover: function(obj) { objPool.push(obj); } } };
var iframeFactory = objectPoolFactory(function() { var iframe = document.createElement('iframe'); document.body.appendChild(iframe);
iframe.onload= function() { iframe.onload = null; iframeFactory.revover(iframe); };
return iframe; });
var iframe1 = iframeFactory.create(); iframe1.src='http://je.ishang.club/';
var iframe2 = iframeFactory.create(); iframe2.src='http://blog.xinshangshangxin.com/';
setTimeout(function() { var iframe3 = iframeFactory.create(); iframe3.src='http://nggather.coding.io/'; }, 3000);
|
结果只有2个iframe
参考文档
- 实体书:
JavaScript设计模式与开发实践(曾探)
文章若有纰漏请大家补充指正,谢谢~~
http://blog.xinshangshangxin.com SHANG殇