目录
1.定义
代理模式是为一个对象提供一个代用品或占位符,以便空值对它的访问。
2.分类
- 虚拟代理:在代理中把一些开销很大的对象,延迟到真正需要它的时候才去创建。
- 缓存代理:为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
- 保护代理:用于对象应该有不同访问权限的情况。
- 防火墙代理:控制网络资源的访问,保护主题不让“坏人”接近。
- 远程代理:为一个对象在不同的地址空间提供局部代表,在Java中,远程代理可以是另一个虚拟机中的对象。
- 智能引用代理:取代了简单的指针,它在访问对象时执行一些附加操作,比如计算一个对象被引用的次数。
- 写时复制代理:通常用于复制一个庞大对象的情况。写时复制代理延迟了复制的过程,当对象被真正修改时,才对它进行复制操作。写时复制代理是虚拟代理的一种变体,DLL(操作系统中的动态链接库)是其典型运用场景。
代理模式包括许多小分类,在JavaScript开发中最常用的是虚拟代理和缓存代理。
3.虚拟代理实现加载图片loading
实际开发中,会有不少显示图片的需求,当网速差或图片较大的时候,会出现一片空白,这个时候我们就需要有个loading告知用户正在进行加载操作,等到加载完成才显示真实图片,使得体验性更佳。如下图:
-
不用代理模式实现加载图片loading如下:
const myImage = (function () { const imgNode = document.createElement('img'); document.body.appendChild(imgNode); const img = new Image; img.onload = function () { imgNode.src = img.src; } return { setSrc: function (src) { imgNode.src = 'loading图'; img.src = src; } } })(); myImage.setSrc( '真实图片' );
-
用代理模式实现加载图片loading如下:
// 本体对象 const myImage = (function () { const imgNode = document.createElement('img'); document.body.appendChild(imgNode); return { setSrc: function (src) { imgNode.src = src; } } })(); // 代理对象 const proxyImage = (function () { const img = new Image; img.onload = function () { myImage.setSrc(this.src); // 加载完成后本体设为真实src } return { setSrc: function (src) { myImage.setSrc('loading图片'); // 加载前loading img.src = src; // 让新建的img加载真实图 } } })(); proxyImage.setSrc('真实显示图片');
- 首先创建一个普通的本体对象myImage ,负责往页面中创建一个img标签,并且提供一个对外的setSrc接口,外界调用这个接口设置src属性。
- 接着我们引入代理对象proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的loading图, 来提示用户图片正在加载;加载完成之后再把本地src设置为真实显示图片。
4.为什么要用代理模式?
我们看到,即使不用任何模式也能实现以上功能,而且代码量更少,那用了代理模式的好处在哪?
当使用代理模式时,更加符合单一职责原则和开放-封闭原则。
- 单一职责原则:就一个类(通常也包括对象和函数等)而言,应该仅有一个引起它变化的原因。
- 开放-封闭原则:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。
没有代理模式时,myImage 对象除了负责给img节点设置src外,还要负责显示loading。我们在处理其中一个职责时,有可能因为其强耦合性影响另外一个职责的实现。后面如果因某些情况(图片小、网速快)不需要loading的时候,就需要在MyImage中删除掉相关代码,这就违反了开放-封闭原则。
相反,使用代理模式时,myImage 负责显示图片,proxyImage负责显示loading,它们可以各自变化而不影响对方,符合单一职责原则。代理对象是对于图片加载的扩展,而当我们不需要loading的时候,只需要改成请求本体而不是请求代理对象即可,符合开放-封闭原则。
注:参考书籍《JavaScript设计模式与开发实践》