代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式是一种非常有意义的模式,在生活中可以找到很多代理模式的场景。比如明星的经纪人。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的 访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
1.小明追MM的故事
var Flower = function(){};
var xiaoming ={
sendFlower:function(target){
var flower = new Flower();
target.receiverFlower( flower );
}
};
var A = {
receiverFlower:function(flower){
console.log('收到花'+flower);
}
};
xiaoming.sendFlower(A);
接下来,我们引入代理B,即小明通过B来给A送花:
var Flower = function(){};
var xiaoming ={
sendFlower:function(target){
var flower = new Flower();
target.receiverFlower( flower );
}
};
var B = {
receiverFlower:function(flower){
A.receiverFlower(flower);
}
};
var A = {
receiverFlower:function(flower){
console.log('收到花'+flower);
}
};
xiaoming.sendFlower(B);
此处的代理模式毫无用处,它所做的只是把请求简单地转交给本体。But,此处引入了代理。
现在改变故事背景,假设当A在心情好的时候收到花,小名表白成功的几率60%,而当A在心情差的时候收到花,小明表白的成功率无限趋近于0.
A的朋友B却很了解A,所以小名只管把花交给B,B会监听A的心情变化,然后选择A心情好的时候把花转交给A:
var Flower = function(){};
var xiaoming ={
sendFlower:function(target){
var flower = new Flower();
target.receiverFlower( flower );
}
};
var B = {
receiverFlower:function(flower){
A.listenGoodMood(function(){
A.receiverFlower(flower);
});
}
};
var A = {
receiverFlower:function(flower){
console.log('收到花'+flower);
},
listenGoodMood:function(fn){
setTimeout(function(){
fn();
},10000);
}
};
xiaoming.sendFlower(B);
代理B可以帮助A过滤掉一些请求,不如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理B处被拒绝掉。这种代理叫做保护代理。
假设现实中的花价格不菲,导致在程序世界里,newFlower也是一个代价昂贵的操作,那么我们可以把new Flower的操作交给代理B去执行,代理B会选择在A心情好的时候再执行new Flower,这是代理的另外一种形式,叫做虚拟代理。虚拟代理把一些开销很大的对象,延迟到真正需要它的时候采取创建。
3.虚拟代理实现图片的预加载
在Web开发中,图片预加载是一种常用的技术,如果直接给某个img标签节点设置src属性,由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。
var myImage = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc:function(src){
imgNode.src = src;
}
};
})();
var proxyImage=(function(){
var img = new Image();
img.onload = function(){
myImage.setSrc(this.src);
};
return {
setSrc : function(src){
myImage.setSrc('loading.url');
img.src = src;
}
}
})();
proxyImage.setSrc('the real image url');