代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
定义
代理,顾名思义就是帮助别人做事,GoF对代理模式的定义如下:
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。
使用实例
简单实例
我们来举一个简单的例子,假如小明要送酸奶小妹玫瑰花,却不知道她的联系方式或者不好意思,想委托大叔去送这些玫瑰,那大叔就是个代理,那我们如何来做呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 先声明美女对象
var girl = function (name) {
this.name = name;
};
// 这是小明
var xiaoMing = function (girl) {
this.girl = girl;
this.sendGift = function (gift) {
alert("Hi " + girl.name + ", 小明送你一个礼物:" + gift);
}
};
// 大叔是代理
var proxyTom = function (girl) {
this.girl = girl;
this.sendGift = function (gift) {
(new xiaoMing(girl)).sendGift(gift); // 替dudu送花咯
}
};
|
调用方式:
1
2
|
var proxy = new proxyTom(new girl("酸奶小妹"));
proxy.sendGift("999朵玫瑰");
|
虚拟代理实现图片预加载
在 Web 开发中,图片预加载是一种常用的技术,如果直接给某个 img 标签节点设置 src 属性, 由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张 loading 图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到 img 节点里,这种 场景就很适合使用虚拟代理。
下面我们来实现这个虚拟代理,首先创建一个普通的本体对象,这个对象负责往页面中创建 一个 img 标签,并且提供一个对外的 setSrc 接口,外界调用这个接口,便可以给该 img 标签设置
src 属性:
1
2
3
4
5
6
7
8
9
|
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ) {
imgNode.src = src;
}
}
})();
|
我们把网速调至 5KB/s,然后通过 MyImage.setSrc 给该 img 节点设置 src,可以看到,在图片
被加载好之前,页面中有一段长长的空白时间。
现在开始引入代理对象 proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中
将出现一张占位的菊花图 loading.gif, 来提示用户图片正在加载。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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( './pic.jpg' );
img.src = src;
}
}
})();
proxyImage.setSrc( './loading.gif' );
|
总结
在 JavaScript 开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。 当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。
参考引用资料
汤姆大叔的博客——深入理解JavaScript系列