JavaScript设计模式之代理模式详解
代理模式是非常常见的模式,比如我们使用的VPN工具,明星的经纪人,都是代理模式的例子。但是,有人会疑问,明明可以直接访问对象,为什么中间还要加一个壳呢?这也就说到了代理模式的好处。在我看来,代理模式最大的好处,就是在不动原有对象的同时,可以给原有对象增加一些新的特性或者行为。
/**
*pre:代理模式
*小明追求A,B是A的好朋友,小明比较腼腆,不好意思直接将花交给A,
*于是小明将花交给B,再由B交给A.
*/
//-----------示例1---------
//不使用代理
varFlower=function(){};
varxiaoming={
sendFlower:function(target){
varflower=newFlower();
target.receiveFlower(flower);
}
};
varA={
receiveFlower:function(flower){
console.log("收到花:"+flower);
}
};
xiaoming.sendFlower(A);
//-----------示例2--------------
//使用代理1
varFlower=function(){};
varxiaoming={
sendFlower:function(target){
varflower=newFlower();
B.receiveFlower(flower);
}
};
varB={
receiveFlower:function(flower){
A.receiveFlower(flower);
}
};
varA={
receiveFlower:function(flower){
console.log("收到花:"+flower);
}
};
xiaoming.sendFlower(B);
//-------------示例3---------------
/*
*使用代理2
*从示例1和示例2,看不出使用代理有什么用处,B只不过是从中间转手了一次。
*接下来,我们想一下。给喜欢的人送花,怎样才能提高成功率呢?
*我们都知道,人有心情好和心情差的时候,当美女心情好的时候,送花成功的概率自然要大些。
*于是,我们将代理升级,监听美女的心情,心情好的时候再给她送花。
*为了演示,我们假设2秒后,A的心情变好。
*/
varFlower=function(){};
varxiaoming={
sendFlower:function(target){
varflower=newFlower();
B.receiveFlower(flower);
}
};
varB={
receiveFlower:function(flower){
A.listenGoodMood(function(){
A.receiveFlower(flower);
});
}
};
varA={
receiveFlower:function(flower){
console.log("收到花:"+flower);
},
listenGoodMood:function(fn){
setTimeout(function(){
fn.apply(this,arguments);
},2000);
}
};
xiaoming.sendFlower(B);
//----------示例4---------------
/*
*【代理模式用处】:虚拟代理
*这里以加载图片为例,我们都知道当网络不畅以及图片过大时,图片加载都比较慢,
*为了更好的用户体验,我们都会在原图片未加载完成前,加上loading图片。
**/
//--4_01未使用代理--
varmyImage=(function(){
varimgNode=document.createElement("img");
document.body.appendChild(imgNode);
return{
setSrc:function(src){
this.imgNode.src=src;
}
}
})();
myImage.setSrc("xxx");
//--4_02使用代理--
varproxyMyImage=(function(){
varimg=newImage();
img.onload=function(){
myImage.setSrc(this.src);
};
return{
setSrc:function(src){
myImage.setSrc("loading.jpg");
img.src=src;
}
}
})();
proxyMyImage.setSrc("xxx");
/*
*[注]:这里可以看到代理模式的好处:在不改变原有接口的同时,可以为系统添加新的行为。
*/
//---------示例5---------------
/*
*【代理模式用处】:合并http请求
*这里以选择文件同步为例。
*以往用户同步文件,在用户选中的时候就触发,这种方法做到了实时性,但无疑增加了网络的开销。
*实际在使用的过程中,往往并不需要立刻就同步。
*以下通过代理模式,将在用户选中文件2秒后进行同步请求。
**/
//---包含一段html代码,请自行添加到一个文件中------
点我上传
1
2
3
4
5
6
7
8
9
//--上传文件--
varsynchronizeFile=function(id){
console.log("开始同步文件:"+id);
};
varproxySynchronizeFiles=(function(){
varfileCache=[],
timer;
returnfunction(id){
fileCache.push(id);
if(timer){
return;
}
timer=setTimeout(function(){
synchronizeFile(fileCache.join(","));
clearTimeout(timer);
timer=null;
checkArr.length=0;
},2000);
}
})();
varcheckArr=document.getElementsByTagName("input");
for(vari=0,c;c=checkArr[i++];){
c.onclick=function(){
if(this.checked==true){
proxySynchronizeFiles(this.id);
}
}
}
//------------示例6-----------------
/*
*【代理模式用处】:缓存代理
*以计算器为例,比如计算某些数的乘积,当参数重复时,我们希望不用重复计算,直接返回结果。
*以下用到代理模式做缓存。
*/
varmult=function(){
if(!arguments){
console.log("请输入参数");
return;
}
vara=1;
for(vari=0,b;b=arguments[i++];){
a=a*b;
}
returna;
};
varproxyMult=(function(){
varcache={};
returnfunction(){
varstr=Array.prototype.join.call(arguments,",");
if(strincache){
console.log("重复return.");
returncache[str];
}
returncache[str]=mult.apply(this,arguments);
}
})();
console.log(proxyMult(2,3,4));
console.log(proxyMult(2,3,4));
//------------示例7--------------
/*
*缓存代理升级-通用版计算
*
*/
varmult=function(){
if(!arguments){
return;
}
vart=1;
for(vari=0,a;a=arguments[i++];){
t=t*a;
}
returnt;
};
varplus=function(){
if(!arguments){
return;
}
vart=0;
for(varaofarguments){
t+=a;
}
returnt;
};
varcreateProxyCaculate=function(fn){
varcache={};
returnfunction(){
varstr=Array.prototype.join.call(arguments,",");
if(strincache){
console.log("重复return"+str);
returncache[str];
}
returncache[str]=fn.apply(this,arguments);
}
};
varproxyMult=createProxyCaculate(mult);
varproxyPlus=createProxyCaculate(plus);
console.log(proxyMult(2,3,4));
console.log(proxyMult(2,3,4));
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。