• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JavaScript设计模式--享元模式

武飞扬头像
此时奋飛
帮助1

一、定义

享元(flyweight)模式是一种用于性能优化的模式,核心是运用共享技术来有效支持大量细刻度的对象。
在JavaScript中,浏览器特别是移动端的浏览器分配的内存并不算多,如何节省内存就成了一个非常有意义的事情。
享元模式是一种用时间换空间的优化模式

内衣工厂有100种男士内衣、100中女士内衣,要求给每种内衣拍照。如果不使用享元模式则需要200个塑料模特;使用享元模式,只需要男女各1个模特。

二、什么场景下使用享元模式?

(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);
        }
    };
}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibhjcb
系列文章
更多 icon
同类精品
更多 icon
继续加载