设计模式之代理模式(Proxy)
文章目录
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
定义
代理,顾名思义就是帮助别人做事,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 开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。 当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。
参考引用资料
文章作者 ZHIKING
上次更新 2017-03-29