设计模式-代理模式
创始人
2025-05-31 00:06:36
0

参考资料

  • 曾探《JavaScript设计模式与开发实践》;

  • JavaScript设计模式之代理模式

定义


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

使用场景:

  • 图片预加载;

  • 缓存数据;

  • 本地开发设置代理,解决跨域问题;

虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要预先猜测是否需要使用代理模式。当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。

代理的意义


  • 单一职责原则:一个类(通常包括对象和函数等)而言,应该仅有一个引起它变化的原因。

保护代理和虚拟代理


代理B可以帮助A过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理B处被拒绝掉,这种代理叫做保护代理。假设现实中花的价格不菲,导致在程序世界里,new Flower也是一个代价昂贵的操作,那么我们可以把new Flower的操作交给代理B去执行,代理B会选择在A心情好时在执行new Flower,这种代理叫做虚拟代理。虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。保护代理用于控制不同权限的对象对目标对象的访问。保护代理用于控制不同权限的对象对目标对象的访问,而虚拟代理是最常用的一种代理模式。

虚拟代理实现图片预加载


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( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );img.src = src;}}
})();
proxyImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

虚拟代理合并HTTP请求


假设我们在做一个文件同步的功能,当我们选中一个checkbox的时候,它对应的文件就会被同步到另外一台服务器上面,此时,我们的思路就是当checkbox被选中时,把选中的文件传到另一台服务器。代码如下:

var synchronousFile = function (id) {console.log('开始同步文件', id)
}
​
var checkbox = document.getElementsByTagName('input')
​
for (var i = 0, c; c = checkbox[i++]) {c.onclick = function() {if (this.checked === true) {synchronousFile(this.id);}}
}

虽然功能实现了,但是会存在很多问题:当我们连续快速点击时,会发送很多个请求,这会带来相当大的开销。我们的解决方案是,通过一个代理函数proxySynchronousFile来收集一段时间之内的请求,最后一次性发给服务器,如果不是实时性要求很高的系统,有一点延迟并不会带来太大的副作用,却能大大减轻服务器的压力。代码如下:

var synchronousFile = function (id) {console.log('开始同步文件', id)
}
​
var proxySynchronousFile = function() {var cache = [],timer;return function(id) {cache.push(id);if (timer) {return;}timer = settimeout(() => {synchronousFile(cache.join(','));clearTimeout(timer);timer = null;cache.length = 0; // 清空id集合}, 2000)}
}()
​
var checkbox = document.getElementsByTagName('input')
​
for (var i = 0, c; c = checkbox[i++]) {c.onclick = function() {if (this.checked === true) {proxySynchronousFile(this.id);}}
}

缓存代理


缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前的一致,则可以直接返回前面的存储的运算结果。这里引用书中缓存代理的例子-计算乘积来理解一下缓存代理的功能:

var mult = function() {var a = 1;for (var i = 0, l = argumments.length; i < l; i++) {a = a * arguments[i];}return a;
}
​
mult(2, 3) // 6
mult(2, 3, 4) // 24
加入缓存代理函数:
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

当第二次调用proxyMult(1, 2, 3, 4)时,本体mult函数并没有被计算,proxyMult直接返回了之前计算好的结果。通过增加缓存代理的方式,mult函数可以继续专注于自身的职责——计算乘积,缓存功能是由代理对象实现的。

缓存分页数据


分页场景在平时的开发中是非常常见的了,通常我们的做法是,每次切换分页时,都重新请求一次接口,如果对于一些不会经常变动的列表来说,每次重新请求就没有必要了,此时我们可以类比前面的缓存代理-计算乘积的例子,缓存一下分页数据:

const getList = function(page) {return axios.get('/api/list', { page })
},
​
const proxyGetList = function() {const cache = {}
​return async function(page) {if (cache[page]) {return cache[page]}const list = await getList(page)cache[page] = listreturn list}
}

这种方式虽然可以减少不少的接口请求,但由于使用缓存数据,容易导致数据不能及时的更新,所以在实际的开发中,我并没有使用这种方式优化。而对于一些项目配置信息,例如用户信息等,我们完全可以通过vuex进行保存数据,当然,如果明确列表数据不会发生变化也可以考虑使用代理模式缓存下不同页数的数据,还是根据具体的场景来决定了。

其他的代理模式


  • 防火墙代理:控制网络资源的访问,保护”主题“不让坏人接近;

  • 远程代理:为一个对象在不同的地址空间提供局部代表,在Java中,远程代理可以是另一个虚拟机中的对象;

  • 智能引用代理:取代了简单的指针,它在访问对象时执行一些附加操作,比如计算一个对象被引用的次数;

  • 写时复制代理:通常用于复制一个庞大对象的情况。写时复制代理延迟了复制的过程,当对象被真正修改时,才对它进行复制操作。写时复制代理是虚拟代理的一种变体,DLL(操作系统中的动态链接库)是典型的应用场景。

相关内容

热门资讯

安卓系统和oppo系统哪个流畅... 你有没有想过,手机系统哪个更流畅呢?安卓系统和OPPO系统,这两个名字听起来就让人心动。今天,咱们就...
安卓怎么用微软系统,利用微软系... 你是不是也和我一样,对安卓手机上的微软系统充满了好奇?想象那熟悉的Windows界面在你的安卓手机上...
安卓系统如何安装nfc,安卓系... 你有没有想过,用手机刷公交卡、支付账单,是不是比掏出钱包来得酷炫多了?这就得归功于NFC技术啦!今天...
ios系统可以转安卓,跨平台应... 你有没有想过,你的iPhone手机里的那些宝贝应用,能不能搬到安卓手机上继续使用呢?没错,今天就要来...
iOSapp移植到安卓系统,i... 你有没有想过,那些在iOS上让你爱不释手的app,是不是也能在安卓系统上大放异彩呢?今天,就让我带你...
现在安卓随便换系统,探索个性化... 你知道吗?现在安卓手机换系统简直就像换衣服一样简单!没错,就是那种随时随地、随心所欲的感觉。今天,就...
安卓系统安装按钮灰色,探究原因... 最近发现了一个让人头疼的小问题,那就是安卓手机的安装按钮突然变成了灰色,这可真是让人摸不着头脑。你知...
安卓7.1.1操作系统,系统特... 你知道吗?最近我在手机上发现了一个超级酷的新玩意儿——安卓7.1.1操作系统!这可不是什么小打小闹的...
安卓os系统怎么设置,并使用`... 你有没有发现,你的安卓手机有时候就像一个不听话的小孩子,有时候设置起来真是让人头疼呢?别急,今天就来...
安卓降低系统版本5.1,探索安... 你知道吗?最近安卓系统又来了一次大动作,竟然把系统版本给降到了5.1!这可真是让人有点摸不着头脑,不...
解放安卓系统被保护,解放安卓系... 你有没有想过,你的安卓手机其实可以更加自由地呼吸呢?是的,你没听错,我说的就是解放安卓系统被保护的束...
校务帮安卓系统下载,便捷校园生... 你有没有想过,你的手机里装了一个神奇的助手——校务帮安卓系统下载?没错,就是那个能让你轻松管理学校事...
安卓系统没有拼多多,拼多多崛起... 你知道吗?最近我在手机上发现了一个小小的秘密,那就是安卓系统里竟然没有拼多多这个应用!这可真是让我大...
甜城麻将安卓系统,解锁全新麻将... 你有没有听说过那个超级火的甜城麻将安卓系统?没错,就是那个让无数麻将爱好者为之疯狂的软件!今天,就让...
安卓系统卸载的软件,深度揭秘卸... 手机里的软件越来越多,是不是感觉内存不够用了?别急,今天就来教你怎么在安卓系统里卸载那些不再需要的软...
安卓系统推荐好游戏,畅享指尖乐... 手机里的游戏可是咱们休闲娱乐的好伙伴,尤其是安卓系统的用户,选择面那可是相当广呢!今天,就让我来给你...
王者安卓系统怎么卖,揭秘如何轻... 你有没有听说最近王者安卓系统的火爆程度?没错,就是那个让无数玩家沉迷其中的王者荣耀!今天,我就来给你...
安卓开发系统内置证书,基于安卓... 你有没有想过,你的安卓手机里那些神秘的内置证书,它们到底是个啥玩意儿?别急,今天就来给你揭秘这些隐藏...
荣耀安装安卓原生系统,深度体验... 你知道吗?最近荣耀手机界可是掀起了一股热潮,那就是——荣耀安装安卓原生系统!这可不是什么小打小闹,而...
安卓13小米系统,创新功能与流... 你知道吗?最近安卓13系统可谓是风头无两,各大手机厂商纷纷推出自家的新版系统,其中小米的安卓13系统...