当前位置: 首页 > 编程笔记 >

学习JavaScript设计模式之享元模式

贲高寒
2023-03-14
本文向大家介绍学习JavaScript设计模式之享元模式,包括了学习JavaScript设计模式之享元模式的使用技巧和注意事项,需要的朋友参考一下

一、定义

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

希望本文所述对大家学习javascript程序设计有所帮助。

 类似资料:
  • 本文向大家介绍学习JavaScript设计模式之策略模式,包括了学习JavaScript设计模式之策略模式的使用技巧和注意事项,需要的朋友参考一下 把不变的部分和变化的部分隔开是每个设计模式的主题。 条条大路通罗马。我们经常会遇到解决一件事情有多种方案,比如压缩文件,我们可以使用zip算法、也可以使用gzip算法。其灵活多样,我们可以采用策略模式解决。 一、定义 定义一系列的算法,把它们一个个封装

  • 本文向大家介绍学习JavaScript设计模式之代理模式,包括了学习JavaScript设计模式之代理模式的使用技巧和注意事项,需要的朋友参考一下 明星都有经纪人作为代理。如果请明星办一场商演,只能联系其经纪人,经纪人会把商演的细节和报酬谈好,再把合同交给明星签。 一、定义 代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。 代理分为:保护代理和虚拟代理 保护代理:用于控制不同权限的

  • 本文向大家介绍学习JavaScript设计模式之状态模式,包括了学习JavaScript设计模式之状态模式的使用技巧和注意事项,需要的朋友参考一下 状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。 当电灯开着,此时按下开关,电灯会切换到关闭状态;再按一次开关,电灯又将被打开。同一个开关在不同的状态下,表现出来的行为是不一样的。 一、有限状态机 状态总数(state)

  • 介绍 享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。 享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数以外,开销基本相同的 话,就可以大幅度较少需要实例化的类的数量。如果能把那些参数移动到类实例的外面,在方法调用的时候将他们

  • 本文向大家介绍学习JavaScript设计模式之模板方法模式,包括了学习JavaScript设计模式之模板方法模式的使用技巧和注意事项,需要的朋友参考一下 一、定义 模板方法是基于继承的设计模式,可以很好的提高系统的扩展性。 java中的抽象父类、子类 模板方法有两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。 二、示例 Coffee or Tea (1) 把水煮沸 (2) 用沸水浸

  • 本文向大家介绍学习JavaScript设计模式之观察者模式,包括了学习JavaScript设计模式之观察者模式的使用技巧和注意事项,需要的朋友参考一下 一、定义 观察者模式(发布-订阅模式):其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 在JavaScript中,一般使用事件模型来替代传统的观察者模式。 好处: (1)可广泛应用于异步编程中,是一种