享元(flyweight)模式的主要作用:性能优化
当系统创建过多相似的对象而导致内存占用过高,可以采用这种设计模式进行优化。
享元模式将对象的属性区分为内部状态与外部状态
内部状态在创建的时候赋值,外部状态在实际需要用到的时候进行动态赋值
对于内部状态和外部状态的区分,有2点:
1、内部状态存储于对象内部
2、内部状态可以被一些对象共享
3、内部状态独立于具体场景,通常不会改变
4、外部状态取决于具体场景,并根据场景变化,外部状态不能被共享。
举例
1、男女模特试衣服
若为每个模特对象Model均设置性别sex,underwear两个属性,每次试衣均创建了一次对象,会导致过多的对象。
由享元模式优化后,Model对象仅sex一个属性,而underwear属性在需要的时候才进行赋值
const Model = function(sex) { this.sex = sex; } Model.prototype.takePhoto = function() { console.log(‘sex= ‘ + this.sex + ‘underwear‘ + this.underwear); } const maleModel = new Model(‘male‘); const femaleModel = new Model(‘female‘); for(let i = 1; i <= 50; i++) { maleModel.underwear = ‘underwear‘ + i; femaleModel.takePhoto(); } for(let j = 1; j <= 50; j++) { femaleModel.underwear = ‘underwear‘ + j; femaleModel.takePhoto(); }
2、文件上传
为优化前
let id = 0; window.startUpload = function(uploadType, files) { for(let i = 0, file; file = files[i++];) { const uploadObj = new Upload(uploadType, file.fileName, file.fileSize); uploadObj.init(id++); } } const Upload = function(uploadType, fileName, fileSize) { this.uploadType = uploadType; this.fileName = fileName; this.fileSize = fileSize; this.dom = null; } Upload.prototype.init = function(id) { this.id = id; this.dom = document.createElement(‘div‘); ...创建上传成功的fileName和fileSize相关展示DOM、绑定删除事件delFile()、插入DOM } Upload.prototype.delFile = function() { ...删除DOM节点及对象 }
调用
startUpload(‘plugin‘, [ { fileName: ‘1.txt‘, fileSize: 1000, }, { fileName: ‘2.txt‘, fileSize: 3000, }, { fileName: ‘3.txt‘, fileSize: 5000, }, ]);
用享元模式优化后
const Upload = function(uploadType) { this.uploadType = uploadType; } Upload.prototype.delFile = function(id) { uploadManager.setExternalState(id, this); ...删除DOM } const UploadFactory = (function() { const createdFlyWeightObjs = {}; return { create(uploadType) { if (createdFlyWeightObjs[uploadType]) { return createdFlyWeightObjs[uploadType]; } return createdFlyWeightObjs[uploadType] = new Upload(uploadType); } } })(); const uploadManager = (function() { const uploadDatabase = {}; return { add(id, uploadType, fileName, fileSize) { // 仅仅创建基本type const flyWeightObj = UploadFactory.create(uploadType); ...添加展示的DOM和相应的删除事件delFile() // 存放额外的属性,通过调用 setExternalState() 函数将以下属性赋值到flyWeightObj上 uploadDatabase[id] = { fileName, fileSize, dom, }; return flyWeightObj; }, setExternalState(id, flyWeightObj) { const uploadData = uploadDatabase[id]; for(const i in uploadData) { flyWeightObj[i] = uploadData[i]; } }, } })(); // 开始出发上传动作的startUpload函数 let id = 0; window.startUpload = function(uploadType, files) { for(let i = 0, file; file = files[i++];) { const uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize); } } // 使用 startUpload(‘plugin‘, [ { fileName: ‘1.txt‘, fileSize: 1000, }, { fileName: ‘2.txt‘, fileSize: 3000, }, { fileName: ‘3.txt‘, fileSize: 5000, }, ]);
对象池示例
页面上要动态创建、删除DOM节点,可以将创建的DOM用完后存放在内存中,需要的时候直接拿出来,而不是再创建
const objectPoolFactory = function(createObjFn) { const objectPool = []; return { create() { const obj === objectPool.length ? createObjFn.apply(this, arguments) : objectPool.shift(); return obj; } recover(obj) { objectPool.push(obj); } } } const iframeFactory = objectPoolFactory(function() { const iframe = document.createElement(‘iframe‘); document.body.appendChild(iframe); iframe.onload = function() { iframe.onload = null; iframeFactory.recover(iframe); } return iframe; }); const iframe1 = iframeFactory.create(); iframe1.src = ‘http://baidu.com‘; const iframe2 = iframeFactory.create(); iframe2.src = ‘http://QQ.com‘;
参考文献:
[1] 《JavaScript设计模式与开发时间》,曾探,中国工信出版集团.
原文地址:https://www.cnblogs.com/yijingzheng/p/10367101.html
时间: 2024-10-12 15:56:29