定义:
代理模式:为一个对象找一个替代对象,以便对原对象进行访问。在我的理解钟,代理就类似于第三方,比如,电视剧中的某大亨出现意外情况的时候,基本都会让律师全权代理,不会直接和大亨进行沟通,律师所做的事情就可以理解为代理模式。还有就是代购这个职业,比如我们因为各种原因不能出国去购买某种化妆品,这时候,代购的作用就显而易见了,她可以代替你出国去购买你所需要的东西,而你不需要出国。这也是符合代理模式的。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。
使用代理的原因是我们不愿意或者不想对原对象直接进行操作。
先来一个简单的例子,代购买化妆品的例子
// 化妆品类var cosmetic = function(name) { this.name = name;}cosmetic.prototype.getName = function() { return this.name;}// 定义不能出国的人var people = { buyCosmetic: function(name) { console.log('请帮我代购'+ name) }}// 定义代购对象var purchasing = { buyCosmetic: function(cosmetic) { people.buyCosmetic(cosmetic.getName()) }} purchasing.buyCosmetic(new cosmetic('口红'))
ES6所提供Proxy
构造函数能够让我们轻松的使用代理模式:
var proxy = new Proxy(target, handler);
Proxy
构造函数传入两个参数,第一个参数target
表示所要代理的对象,第二个参数handler
也是一个对象用来设置对所代理的对象的行为。如果想知道Proxy
的具体使用方法,可参考阮一峰的。
虚拟代理:是把一些开销很大的对象,延迟到真正需要它的时候才去创建执行
我们在浏览一些购物商城的时候,会发现,当网络不太好的情况下,有些图片是加载不出来的,会有暂无图片的一张图片去代替它实际的图片,等网路图片加载完成之后,暂无图片就会被实际的图片代替。这就是使用的图片的懒加载。图片的懒加载也可是使用虚拟代理的模式来进行设计。
// 图片懒加载 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) { console.log('src', src) myImage.setSrc('http://seopic.699pic.com/photo/40007/8839.jpg_wh1200.jpg'); img.src = src; } }})();proxyImage.setSrc('http://seopic.699pic.com/photo/40006/7735.jpg_wh1200.jpg')
缓存代理::可以作为一些开销大的运算结果提供暂时的存储,下次运算时,如果传递进来堵塞参数跟之前一致,则可以直接返回前面存储的运算结果。
例如,前后端分离,向后端请求分页的数据的时候,每次页码改变时都需要重新请求后端数据,我们可以将页面和对应的结果进行缓存,当请求同一页的时候,就不再请求后端的接口而是从缓存中去取数据。
const getFib = (number) => { if (number <= 2) { return 1; } else { return getFib(number - 1) + getFib(number - 2); }}const getCacheProxy = (fn, cache = new Map()) => { return new Proxy(fn, { apply(target, context, args) { const argsString = args.join(' '); if (cache.has(argsString)) { // 如果有缓存,直接返回缓存数据 console.log(`输出${args}的缓存结果: ${cache.get(argsString)}`); return cache.get(argsString); } const result = fn(...args); cache.set(argsString, result); return result; } })}const getFibProxy = getCacheProxy(getFib);getFibProxy(40); // 102334155getFibProxy(40); // 输出40的缓存结果: 102334155
使用场景:
代理模式的类型较多,不同类型的代理模式有不同的优缺点,它们应用于不同的场合:
(1) 当客户端对象需要访问远程主机中的对象时可以使用远程代理。
(2) 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理,例如一个对象需要很长时间才能完成加载时。
(3) 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理。通过使用缓冲代理,系统无须在客户端每一次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可。
(4) 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。
(5) 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理。
优缺点:
优点:代理模式能够将代理对象与被调用的对象分离,降低了系统的耦合度。代理模式在客户端和目标对象之间起到一个中介作用,这样,可以起到保护目标对象的作用。代理对象也可以对目标对象调用之前进行其他的操作。
缺点:; 增加系统的复杂度