1. 享元模式

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

1.1 传统的文件上传方法

以文件上传为例,文件上传功能可以选择依照队列,一个一个的排队上传,也支持同时选择2000个文件。
假如每一个文件都对应着一个JavaScript上传对象的创建,2000个文件就会同时创建2000个upload对象
假设这里的文件上传支持插件和flash两种

var id=0;
window.startUpload=function(uploadType,files){//uploadType区分是控件还是flash
for(var i=0,file;file=files[i++];){
var uploadObj=new Upload(uploadType,file.fileName,file.fileSize);
uploadObj.init(id++);//给upload对象设置一个唯一的id
}
}; var Upload=function(uploadType,fileName,fileSize){
this.uploadType=uploadType;
this.fileName=fileName;
this.fileSize=fileSize;
this.dom=null;
}; Upload.prototype.init=function(id){
var that=this;
this.id=id;
this.dom=document.createElement('div');
this.dom.innerHTML=
'<span>文件名称:'+this.fileName+',文件大小:'+this.fileSize+'</span>'
+'<button class="delFile">删除</button>';
this.dom.querySelector('.delFile').onclick=function(){
that.delFile();
};
document.body.appendChild(this.dom);
}; Upload.prototype.delFile=function(){
return this.dom.parentNode.removeChild(this.dom);
};

接下来分别创建3个插件上传对象和3个flash上传对象

startUpload('plugin',[
{
fileName:'1.txt',
fileSize:1000
},
{
fileName:'2.html',
fileSize:3000
},
{
fileName:'3.txt',
fileSize:5000
}
]); startUpload('flash',[
{
fileName:'4.txt',
fileSize:1000
},
{
fileName:'5.html',
fileSize:3000
},
{
fileName:'6.txt',
fileSize:5000
}
]);

这里一共有6个需要上传的文件,一共创建了6个upload对象

1.2 享元模式重构文件上传

划分内部状态和外部状态的关键主要有以下几点

  • 内部状态储存于对象内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体的场景,通常不会改变
  • 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享

首先,需要确认插件类型uploadType是内部状态
upload对象必须依赖uploadType属性才能工作,因为插件上传、flash上传各自调用的接口是完全不一样的
fileName和fileSize是根据场景而变化,每个文件的fileName和fileSize都不一样,fileName和fileSize没有办法被共享,它们是外部状态

剥离外部状态

var Upload=function(uploadType){
this.uploadType=uploadType;
};

Upload.prototype.init函数不再需要,upload对象初始化工作被放在后面定义的uploadManager.add函数里面
接下来只需要定义Upload.prototype.delFile函数

Upload.prototype.delFile=function(id){
uploadManager.setExternalState(id,this);
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);
}
}
})();

管理器封装外部状态
完善前面提到的uploadManager对象,它负责向UploadFactory提交创建对象的请求
并用uploadDatabase对象保存所有的upload对象的外部状态

var uploadManager=(function(){
var uploadDatabase={};
return {
add:function(id,uploadType,fileName,fileSize){
var flyWeightObj=UploadFactory.create(uploadType);
var dom=document.createElement('div');
dom.innerHTML=
'<span>文件名称:'+this.fileName+',文件大小:'+this.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];
}
}
}
})();

触发上传动作的startUpload函数

var id=0;
window.startUpload=function(uploadType,files){
for(var i=0,file;file=files[i++];){
var uploadObj=uploadManager.add(++id,uploadType,file.fileName,file.fileSize);
}
};

接下来分别创建3个插件上传对象和3个flash上传对象

startUpload('plugin',[
{
fileName:'1.txt',
fileSize:1000
},
{
fileName:'2.html',
fileSize:3000
},
{
fileName:'3.txt',
fileSize:5000
}
]); startUpload('flash',[
{
fileName:'4.txt',
fileSize:1000
},
{
fileName:'5.html',
fileSize:3000
},
{
fileName:'6.txt',
fileSize:5000
}
]);

这里一共有6个需要上传的文件,一共创建了2个upload对象
一个是插件类型的upload对象,一个是flash类型的upload对象

1.3 对象池技术

对象池也是一种共享相关的技术,对象池维护一个装载空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池获取
如果此时对象池里没有空闲对象,则创建一个新的对象

通用对象池实现

var objectPoolFactory=function(createObjFn){
var objectPool=[];
return {
create:function(){
var obj=objectPool.length === 0 ?
createObjFn.apply(this,arguments):objectPool.shift();
return obj;
},
recover:function(obj){
objectPool.push(obj);
}
}
};

利用objectPoolFactory创建一个装载iframe的对象池

var iframeFactory=objectPoolFactory(function(){
var iframe=document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload=function(){
iframe.onload=null;
iframeFactory.recover(iframe);//加载完成后,回收节点
}
return iframe;
}); setTimeout(function(){
var iframe=iframeFactory.create();
iframe.src='http://www.qq.com';
},1000);

这里每隔1秒通过工厂方法创建一个iframe,但是采用上述对象池,始终只会生产一个iframe对象

《JavaScript设计模式与开发实践》读书笔记之享元模式的更多相关文章

  1. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  2. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

  3. Javascript设计模式与开发实践读书笔记(1-3章)

    第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用   多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...

  4. javascript设计模式与开发实践阅读笔记(8)——观察者模式

    发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...

  5. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  6. javascript设计模式与开发实践阅读笔记(6)——代理模式

    代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...

  7. javascript设计模式与开发实践阅读笔记(4)——单例模式

    定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...

  8. 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式

    第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...

  9. 《JavaScript设计模式与开发实践》笔记第一章

    第一章 面向对象的JavaScript 动态类型语言和鸭子类型 编程语言按照数据类型大体可以分为两类:静态类型语言.动态类型语言. 静态类型语言:在编译时便已确定变量的类型. 优点: 在编译时就能发现 ...

随机推荐

  1. Thinkphp入门 二 —空操作、空模块、模块分组、前置操作、后置操作、跨模块调用(46)

    原文:Thinkphp入门 二 -空操作.空模块.模块分组.前置操作.后置操作.跨模块调用(46) [空操作处理] 看下列图: 实际情况:我们的User控制器没有hello()这个方法 一个对象去访问 ...

  2. [置顶] JSP分页,使用Hibernate+mysql

    此代码为博主参考巴巴运动网源码所得,大部分一样,略有修改,在这里分享给大家,也方便自己以后写代码直接copy,看网上很多分页代码JSP里是用JAVA代码,博主原来也是这样,看到源码了解了JSTL,建议 ...

  3. kgdb接收一个数据包详解

    0    kdb>kgdb  // 可进入kgdb 模式    if (dbg_kdb_mode) {             error = kdb_stub(ks);     } else ...

  4. Android 高手进阶,自己定义圆形进度条

    背景介绍 在Android 开发中,我们常常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,许多时候须要我们自定义控件,在开发的过程中.我们公司遇到了一种须要自己写的一 ...

  5. ScaleAnimation类:尺寸变化动画类

    9.4  ScaleAnimation类:尺寸变化动画类 ScaleAnimation类是Android系统中的尺寸变化动画类,用于控制View对象的尺寸变化,该类继承于Animation类.Scal ...

  6. Swift - 环形进度条(UIActivityIndicatorView)的用法

    Swift中,除了条形进度条外,还有环形进度条,效果图如下: 1,环形进度条的基本属性 (1)Style: Large White:比较大的白色环形进度条 White:白色环形进度条 Gray:灰色环 ...

  7. TApplication.Initialize的前世今生

    ---------------------------------------------------------------------------------------------------- ...

  8. Android菜鸟的成长笔记(11)——Android中的事件处理

    原文:[置顶] Android菜鸟的成长笔记(11)——Android中的事件处理 Android提供了两种方式来处理事件,一个是基于回调的事件处理,另一个是基于监听的事件处理,举个例子: 基于回调的 ...

  9. unity中怎样获取全部子物体的组件

    public GameObject[] obj;     void Awake()     {             for (int i = 0; i < obj.Length; i++) ...

  10. SharePoint场管理-PowerShell(二)

    1. 合并Log文件 Merge-SPLogFile –Path E:\Logs\MergedLog.log –StartTime "1/19/2010" –Overwrite 2 ...