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

相关内容

热门资讯

iPhone手机怎么玩安卓系统... 你有没有想过,你的iPhone手机竟然也能玩安卓系统?没错,就是那个一直以来让你觉得遥不可及的安卓世...
平板删安卓系统更新不了,原因及... 最近是不是你也遇到了这样的烦恼?平板电脑上的安卓系统更新不了,是不是让你头疼得要命?别急,今天就来给...
苹果组装机安卓系统卡,卡顿背后... 你有没有发现,最近用苹果手机的时候,有时候系统有点卡呢?这可真是让人头疼啊!你知道吗,其实这背后还有...
安卓系统原生浏览器,功能与体验... 你有没有发现,每次打开手机,那个小小的浏览器窗口总是默默无闻地在那里,陪你浏览网页、搜索信息、看视频...
安卓机如何上苹果系统,跨平台体... 你是不是也和我一样,对安卓机和苹果系统之间的切换充满了好奇?想象你的安卓手机里装满了各种应用,而苹果...
安卓导入系统证书失败,原因分析... 最近在使用安卓手机的时候,你是不是也遇到了一个让人头疼的问题——导入系统证书失败?别急,今天就来给你...
安卓原生系统有哪些手机,盘点搭... 你有没有想过,为什么有些手机用起来就是那么流畅,那么顺心呢?这背后可大有学问哦!今天,就让我带你一起...
安卓系统关机了怎么定位,安卓系... 手机突然关机了,是不是有点慌张呢?别担心,今天就来教你一招,让你的安卓手机即使关机了,也能轻松定位到...
安卓系统游戏加速器,畅享无延迟... 你有没有发现,手机游戏越来越好玩了?不过,有时候游戏体验可能并不那么顺畅,是不是因为手机性能不够强大...
安卓4系统天气功能,尽在掌握 安卓4系统天气功能大揭秘在当今这个数字化的世界里,手机已经不仅仅是一个通信工具,它更是一个集成了各种...
安卓系统如何玩碧蓝幻想,攻略与... 你有没有想过,在安卓系统上玩《碧蓝幻想》竟然可以这么酷炫?没错,就是那个让你沉迷其中的二次元大作!今...
安卓系统搜不到图朵,图朵生成之... 最近是不是你也遇到了这样的烦恼?手机里明明有那么多美美的图片,但是用安卓系统搜索的时候,却怎么也找不...
魁族8刷安卓系统,系统升级后的... 哇,你知道吗?最近在安卓系统圈子里,有一个话题可是引起了不小的轰动,那就是魁族8刷安卓系统。你是不是...
微信正版安装安卓系统,畅享沟通... 你有没有想过,你的微信是不是正版安装的安卓系统呢?这可不是一个小问题哦,它关系到你的微信使用体验和隐...
电视能刷安卓系统吗,电视也能刷... 电视能刷安卓系统吗?揭秘智能电视的无限可能想象你家的电视不再只是用来观看节目的工具,而是变成了一个功...
安卓系统开通通知功能,畅享智能... 你知道吗?最近安卓系统更新后,新增了一个超级实用的功能——开通通知功能!这可是个大喜事,让咱们的生活...
苹果系统安卓爱思助手,系统兼容... 你有没有发现,手机的世界里,苹果系统和安卓系统就像是一对欢喜冤家,总是各有各的粉丝,各有各的拥趸。而...
安卓系统占用很大内存,揭秘内存... 手机里的安卓系统是不是让你感觉内存不够用,就像你的房间堆满了杂物,总是找不到地方放新东西?别急,今天...
安卓系统p30,安卓系统下的摄... 你有没有发现,最近安卓系统P30在手机圈里可是火得一塌糊涂呢!这不,我就来给你好好扒一扒这款手机的那...
siri被安卓系统进入了,智能... 你知道吗?最近科技圈可是炸开了锅,因为一个大家伙——Siri,竟然悄悄地溜进了安卓系统!这可不是什么...