代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象,替身对象对请求做出一些处理之后,再把请求转给本体对象。
代理模式的例子
我们实现一个小明追MM的例子:
var Flower = function(){};
var xiaoming = {
sendFlower:function(target){
var flower = new Flower();
target.receiveFlower(flower);
}
};
var B = {
receiveFlower: function(flower){
A.receiveFlower(flower);
}
};
var A = {
receiveFlower: function(flower){
console.log('收到花:' + flower)
}
};
通过上面的代码我们实现了一个最简单的代理模式。从表面上看起来,明明小明可以直接给A送花为啥要通过代理B。确实在这个例子中代理模式毫无用处,但是如果我们给A增加一个背景设定,假设A在心情好的时候收到花的概率为60%,心情差的时候收到花的概率基本为0,并且花的成本很高,这样实现的例子如下:
var Flower = new function(){};
var xiaoming = {
sendFlower:function(target){
var flower = new Flower();
target.receiveFlower(flvarower);
}
};
var B = {
receiveFlower: function(flower){
A.listenGoodMood(function(){
A.receiveFlower(flower); //监听A的好心情
});
}
};
var A = {
receiveFlower:function(flower){
console.log('收到花:' + flower)
}
listenGoodMood:function(fn){
setTimeout(function(){ //假设10秒后A的心情变好
fn();
},10000)
}
}
保护代理和虚拟代理
代理B可以帮助代理A过滤掉一些请求,比如送花的人中年龄太大或者长相太丑,这种请求可以直接在代理B处被拒绝掉。这种代理叫做保护代理。 假设现实中的话价格不菲,导致在程序世界中,new Flower()是一个代价昂贵的操作,那么我们可以把new Flower的操作交给代理B去执行,代理B会选择在A心情好的时候在执行new Flower()操作,这是代理的两一种形式虚拟代理。
虚拟代理实现图片的预加载
图片加载过程中,我们常见的做法先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc:function(src){
imgNode.src = src;
}
}
})();
var porxyImage = (function(){
var img = new Image();
img.load = function(){
myImage.setSrc(this.src)
}
return {
setSrc: function(src){
myImage.setSrc('file:// /C:/loading.gif');
img.src =src;
}
}
})();
proxyImage.setSrc('http://xxxxx.jpg');
虚拟代理合并HTTP请求
我们做一个文件同步的功能,当我们选中一个checkbox的时候,它对应的文件就会被同步到另一台备用服务器上面:
var synchronousfile = function(id){
console.log('开始同步文件,id为:' + id);
}
var proxySynchronousFile = (function(){
var chache = [],timer;
return function(id){
cache.push(id);
if(timer){ // 保证不会覆盖已启动的定时器
return;
}
timer = setTimeOut(function(){
synchronousfile(cache.join(','));
clearTimeout(timer);
timer = null;
cache.length = 0;
},2000);
}
})();
var checkbox = document.getElementsByTagName('input');
for(var i = 0,c;c=checkbox[i++];){
c.onclick = function(){
if(this.checked === true){
porxySynchronousFile(this.id);
}
}
}
通过一个代理函数porxySynchronousFile 收集2s内的请求,最后一次性发送给服务器。
缓存代理了
var mult = function(){
var a = 1;
for(var i=0,1=arguments.length;i<1,i++){
a = a* arguments[i];
}
return a;
}
//代理缓存
var proxyMult = (function(){
var cache = {};
return function(){
var args = Array.prototype.join.call(arguments,',');
if(args in cache){
return cache[args];
}
return cache[args] = mult.apply(this.arguments);
}
})()
proxyMult(1,2,3,4); //24
proxyMult(1,2,3,4); //缓存中取出 24