千家信息网

javascript设计模式的享元模式怎么实现

发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,这篇文章主要介绍"javascript设计模式的享元模式怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"javascript设计模式的享元模式怎么实现"
千家信息网最后更新 2025年11月11日javascript设计模式的享元模式怎么实现

这篇文章主要介绍"javascript设计模式的享元模式怎么实现"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"javascript设计模式的享元模式怎么实现"文章能帮助大家解决问题。

    一. 认识享元模式

    享元模式:是一种用于性能优化的模式,其核心是运用共享技术来有效支持大量细粒度的对象。

    通俗点来讲就是找出事物很多属性种属性分类最少的一种,利用属性值的个数来分类。比如说有这么一个例子,假如一个工厂需要 20 个男性模特和 20 个女性模特需要穿上 40 件新款衣服拍照做宣传,如果我们不使用享元模式,则需要聘请 40 位模特,这会造成巨大的经济损失,也没有必要,如果使用享元模式通过性别来区分,则只需要一男一女两个模特。下面我们来看代码实现。

    二. 代码具体实现

    1. 不使用享元模式实现上述案例

    分析:这是正常的代码实现,我们一共创建了 40 个对象,我们日常编写代码可能不会注意这种情况,但是在实际开发中如果遇到创建几万个甚至几十万个对象,就会造成严重的性能损耗,浪费内存。

            let Model = function(sex, underwear) {            this.sex = sex;            this.underwear = underwear;        }        Model.prototype.takePhoto = function () {            console.log('sex=' + this.sex + 'underwear = ' + this.underwear);        }        for(let i = 0; i < 20 ; i++){            new Model('男',  'underwear' + i).takePhoto();        }        for(let i = 0; i < 20 ; i++){            new Model('女',  'underwear' + i).takePhoto();        }

    2. 使用享元模式重构上述代码

    分析:代码重构后,我们只创建了两个对象便完成了同样的任务,无论需要多少对象,但是我们只需要创建两个对象,大大提高了性能。

            let ModelR = function( sex ) {            this.sex = sex;        }        let ModelF = new ModelR( '女' );        let ModelM = new ModelR('男');        ModelR.prototype.takePhoto = function () {            console.log('sex=' + this.sex + 'underwear = ' + this.underwear);        }        for(let i = 0; i < 20 ; i++) {            ModelF.underwear = 'underwear' + i;            ModelF.takePhoto();        }        for(let i = 0; i < 20 ; i++) {            ModelM.underwear = 'underwear' + i;            ModelM.takePhoto();        }

    总体分析

    现在我们对享元模式有了一个大致的了解,思想其实很简单,利用所有对象相同的属性来初始化创建对象,上述例子中利用人的性别这个属性来创建对象,而性别这个属性只有男女这两种,因此我们只需要创建两个对象,将衣服作为其他不同的属性添加到对象中便完成了对象的替换,相当于拥有 40 个不同的对象,但是实际只创建了两个。

    因此,我们就引出了一个新的概念,内部状态与外部状态。

    3. 享元模式的状态

    • 内部状态:也就是我们上文提到的属性分类最少的一种,也就是性别,只有两种,可以被对象共享。

    • 外部状态:其他属性,不能被共享。

    结论:剥离了外部状态的对象成为了共享对象,外部对象在必要时被传入共享对象来组装成一个完整的对象,组装外部对象需要花费一定的时间,但节省了大量内存损耗,因此,享元模式是一种时间换空间的优化模式。

    三. 享元模式实际应用

    假如我们需用对文件上传,现在假设有两种上传方式 flashplugin,每一次上传都对应一次 js 对象的创建,如果我们按部就班,当大量文件上传时就会造成浏览器假死状态,因此我们用享元模式来设计代码,首先我们来确定文件的内部状态和外部状态,我们思考下文件有什么属性,文件大小,文件类型,文件上传方式,文件大小和文件类型都是不可控属性,文件上传方式只有两种,因此将文件上传方式作为外部状态,现在我们来编写代码。

            let Upload = function(uploadType) {            this.uploadType = uploadType;        }        Upload.prototype.delFile = function( id ) {            uploadManager.setExternalState(id, this);            if(this.fileSize < 3000) {                return this.dom[xss_clean].removeChild(this.dom);            }        }        // 使用工厂模式来创建对象        let UploadFactory = function() {            let cache = {};            return {                create(uploadType) {                    if(cache[uploadType]){                        return cache[uploadType];                    }                    return cache[uploadType] = new Upload( uploadType );                }            }        }()        // 创建一个管理器封装外部状态        let uploadManager = function() {            uploadDatabase = {};            return {                add(id, uploadType, fileName, fileSize){                    let uploadObj = UploadFactory.create( uploadType );                    let dom = document.createElement('div');                    dom[xss_clean] = `文件名称: ${ fileName },文件大小:${fileSize} `;                    dom.querySelector('#del').onclick = function() {                        uploadObj.delFile( id );                    }                    document.body.appendChild( dom );                    uploadDatabase[ id ] = {                        fileName,                        fileSize,                        dom                    }                    return uploadObj;                },                setExternalState(id, uploadObj){                    let uploadData = uploadDatabase[id];                    for(let i in uploadData) {                        uploadObj[i] = uploadData[i];                    }                }            }        }();        let id = 0;        window.startUpload = function(uploadType, files) {            for(let i = 0,file; file = files[i++];){                let uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);                // 进行上传            }        };        startUpload('plugin', [            {                fileName: '1.txt',                fileSize: 1000            },            {                fileName: '2.txt',                fileSize: 1000            },            {                fileName: '3.txt',                fileSize: 3000            }        ])        startUpload('flash', [            {                fileName: '4.txt',                fileSize: 1000            },            {                fileName: '5.txt',                fileSize: 1000            },            {                fileName: '6.txt',                fileSize: 3000            }        ])

    扩展:再谈内部状态和外部状态

    现在我们思考下,如果没有内部状态或者没有外部状态那有该怎么办。

    • 没有内部状态享元:此时,所有属性作为外部享元,相当于内部享元只有一种,因此我们只需要创建一个对象,此时便相当于之前所提单的单例模式

    • 没有外部状态享元:这时引入一个新的概念,对象池

    四. 对象池

    对象池的应用十分广泛,数据库的连接池就是其重要用武之地。对象池的大多数使用场景就是 DOM 操作,因为 DOM 的创建和删除是 js 种最消耗性能的操作。

    理解对象池非常简单,比如说我们想做一个圆形的月饼,只需要制造一个圆形的模具便可以做无数的圆形月饼,当我们想做方形月饼时,只需要制造一个方形模具,同时将圆形模具保留下来,等再次使用时拿出来直接用便可。对象池就是这样的原理,我们看一下其通用实现代码。

           let objectPoolFactory = function( fn ) {            let pool = [];            return {                create(...args){                    let obj = (pool.length === 0)? fn.apply(this, args) : pool.shift();                    return obj;                },                recover(obj) {                    pool.push(obj);                }            }        }

    实际应用

    我们在地图上搜索几个不同的位置,第一次搜索显示北京的两个景区位置,第二次搜索北京三个饭店的位置。

    分析:第一次需要两个 DOM 节点,因此创建两个节点,之后将其回收,第二次需要三个DOM节点,使用之前的两个,只需要再创建一个新的节点便可,大大提高了代码性能。

            // 创建 dom 节点        let createDomFactory = objectPoolFactory(()=>{            let div = document.createElement('div');            document.body.appendChild(div);            return div;        });        let ary = []; // 用于回收        let name = ['天安门', "长城"];        for(let i = 0, l= name.length; i < l ;i++){            let dom = createDomFactory.create();            dom[xss_clean] = name[i];            ary.push(dom);        }        for(let i = 0, l = ary.length; i < l ; i ++ ){            createDomFactory.recover(ary[i]);        }        let name1 = ["饭店1", "饭店2", "饭店3"];        for(let i = 0, l = name1.length; i < l; i++) {            let dom = createDomFactory.create();            dom[xss_clean] = name1[i];        }

    关于"javascript设计模式的享元模式怎么实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

    对象 模式 状态 文件 属性 代码 两个 实际 性能 节点 设计 不同 只有 圆形 就是 性别 方式 模特 饭店 分析 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 佩奇影视连接服务器失败 数据库在计算机系统地位 2000数据库连接 赌博服务器端了数据看得到吗 局成立网络安全和信息化领导小组 千玺深圳网络技术有限公司 书籍交易系统数据库 网络安全宣传日活动讲话稿 关系数据库三个完整性约束是什么 网络安全知识竞答答题 连云港信息网络技术服务费 利用数据库管理共享文件 自治服务器是什么 网络安全的攻击有哪些方式 蜂鸟网络技术有哪些 pcb测试软件开发 怎么退出服务器管理器 网络安全法的特点包括 vs2015数据库表怎么保存 关于视图的数据库实验 数据库的知识的英文资料 浙江热通道图腾服务器机柜 数据库数据的来源 微博手机服务器异常怎么办 宿州数字视频系统服务器 网络安全法应当遵循什么样的原则 票务系统网络安全 江津软件开发基地 互联网科技公司面试正装 服务器内存能和普通内存共用么
    0