您的位置:首页 > Web前端 > JavaScript

JavaScript设计模式 代理模式

2017-04-08 10:52 232 查看

代理模式是为一个对象提供一个代用品或者占位符,以便控制对它的访问。

代理模式的关建是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际访问的是替身对象,替身对象对请求做出一些处理后,再把请求转交给本体对象。

先来看一个例子,假设A想送花给C,但又不知道C的心情,C的心情好时即送花成功,那么可以通过C的好朋友B来送花,B了解C,可以知道C的心情。

var Flower = function(){};
//A发起送花请求
var A = {
sendFlower:function(target){
var flower = new Flower();
target.receiveFlower(flower);
}
};
//B接受送花请求 并监听到C的心情好时转给C
var B = {
receiveFlower:function(flower){
C.listenGoodMood(function(){
C.receiveFlower(flower);
});
}
};
//C接受送花请求 和 发表心情
var C = {
receiveFlower :function(flower){
console.log(flower);
},
listenGoodMood:function(fn){
setTimeout(function(){
fn();
},1000)
}
};

A.sendFlower(B);

在实际开发中,由于花的价格昂贵,那么可以当B监听到C的好心情时,才创建花来节省消耗。

var B = {
receiveFlower:function(){
C.listenGoodMood(function(){
var  flower = new Flower();
C.receiveFlower(flower);
});
}
};

 

在这个例子中,最关键的就是B对象,也就是该章描述的代理对象,代理B可以帮助C过滤掉那些年龄太大之类的人,这些请求可以被B直接拒绝掉,这种被称为保护代理。而在真正需要的时候才来创建对象,也就是在C心情好的时候才创建花,被称为虚拟代理。

 

下面来看一个实际开发中的例子,通常在加载一个比较大的图片时,我们会先用一张菊花图提示用户化正在加载,当真正的图片被加载完成后,才显示该图片。

//加载图片的类
var myImg = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc:function(src){
imgNode.src = src;
}
}
})();
//代理类,在图片加载完成之前 显示菊花图 加载完成后 改换真正的图片
var proxyImg = (function(){
var img = new Image();
img.onload = function(){
myImg.setSrc(this.src);
};
return {
setSrc:function(src){
myImg.setSrc("菊花图!");
img.src = src;
}
}
})();

proxyImg.setSrc('真正的图片!');

在这里,也许会有疑问,即使不用代理模式也能实现这种效果,先来看一下不用代理的代码实现:

var myImg = (function(){
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
var img = new Image();
img.onload = function(){
myImg.setSrc(this.src);
};
return {
setSrc:function(src){
myImg.setSrc("菊花图!");
img.src = src;
}
}
})();

myImg.setSrc("真正的图片!")

为了说明代理的意义,先引入一个概念,即单一职责原则,表示一个类应该只有一个引起它变化的原因。这保证了类的高内聚和低耦合。

在不使用代理的例子下,myImg负责了给img设置src之外,还要负责预加载的图片,有时候我们的图片可能很小,或者以后的网速很快,那么我们就需要深入到该类来删除预加载的功能。

而如果采用了代理模式,那么当我们不需要预加载时,只需要直接调用myImg就可以了。

 

虚拟代理在惰性加载中的应用。

如一个控制台,当用户输入console.log(0)时,会在控制台打印0,但通常用户并不会一开始就打开控制台,所以也不会一开始就加载控制台。那么我们可以先创建一个代理类,将要打印的信息放进该代理类,当用户按下F12打开控制台的时候,我们创建了控制台之后,再遍历这些信息并输出。

 

代理在zepto类库事件处理中使用得比较多,具体可以参考zepto事件分析系列,其中带有proxy的即为代理对象。

 

参考自Javascript设计模式与开发实践一书。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: