千家信息网

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

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

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

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

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

    三. 享元模式实际应用

    假如我们需用对文件上传,现在假设有两种上传方式 flash 和 plugin,每一次上传都对应一次 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安全错误 数据库的锁怎样保障安全 上海睿民互联网科技有限公司 山东特亿宝互联网科技有限公司 互联网科技公司起名 科技金融是不是互联网金融 互联网科技有限公司经营范围 盈实互联网科技 美国互联网科技巨头监管 重庆互联网络科技 狮子座互联网科技 天下捷融互联网科技 深圳卡尔迅互联网科技有限公司怎么样 互联网实体化科技化 青岛科技大学互联网大赛研究生 辽宁互联网新科技 互联网媒体平台算高科技产业 互联网科技融合创新 高科技和互联网的现代国家 山东亿川互联网科技有限责任公司 颐高云石互联网科技 小牛互联网科技有限公司地址 互联网金融监管科技数据 互联网科技战争 狮子座互联网科技有限公司 互联网科技热点资讯 顶级互联网科技成果有哪些 花神(南京)互联网科技有限公司 晋城互联网科技 皮皮虾互联网科技有限公司 上海乐五互联网科技有限公司 悟空问答互联网科技
    0