设计模式-代理模式
创始人
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(操作系统中的动态链接库)是典型的应用场景。

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...