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. jstorm简介(转)

    Jstorm是参考storm的实时流式计算框架,在网络IO.线程模型.资源调度.可用性及稳定性上做了持续改进,已被越来越多企业使用 作为commiter和user,我还是非常看好它的应用前景,下面是在 ...

  2. map标签的详细使用参数

    map标签必须成对出现,即 <map> ....</map> 同时map必须和area配合使用. img标签里的usermap属性值必须与map标签里的id和name值完全一致 ...

  3. PHP从数据库获取的下拉树

    <?php include "config.php"; include "mysql.php"; $db = new Mysql('test'); //几 ...

  4. arch Failed to load module "intel"

    arch启动x的时候出现问题困扰我一天了,终于解决掉了. 错误如下: [ 61.086] (II) LoadModule: "intel" [ 61.087] (WW) Warni ...

  5. ADO异步查询显示进度条

    一般,ADO都是以同步的方式来处理数据.这就是说,当ADO开始处理数据后,应用程序必须等到ADO处理完毕之后才可以继续执行.但是除了同步执行方式之外,ADO也提供了异步执行的方式,允许当ADO处理时, ...

  6. TP-LINK无线路由器WR340G+ 54M支持WDS - 东莞市泰讯电子科技有限公司

    TP-LINK无线路由器WR340G+ 54M支持WDS - 东莞市泰讯电子科技有限公司 TP-LINK无线路由器WR340G+ 54M支持WDS 品牌  TP-LINK无线路由器 型号  WR340 ...

  7. [IDEs]Eclipse自动格式化代码

    格式化代码快捷键:Ctrl + Shift + F 一般情况: 1).Ctrl + A 2).Ctrl + Shift + F ps: 格式化之后发现代码换行了,因为已经达到最大长度,可修改设置,增加 ...

  8. MQ、JMS以及ActiveMQ

    MQ简介: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们.消息传 ...

  9. ACdream 1135(MST-最小生成树边上2个值,维护第一个最小的前提下让还有一个最小)

    F - MST Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) SubmitStatu ...

  10. Linux 利用hosts.deny 防止暴力破解ssh(转)

    一.ssh暴力破解 利用专业的破解程序,配合密码字典.登陆用户名,尝试登陆服务器,来进行破解密码,此方法,虽慢,但却很有效果. 二.暴力破解演示 2.1.基础环境:2台linux主机(centos 7 ...