js设计模式——代理模式
代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。
关键:当客户不方便直接访问一个对象或者不满足需求的时候,提供一个替身对象来控制这个对象的访问。客户实际上访问的是替身对象。替身对象对请求作出一些请求之后,再把请求交给本体对象。
保护代理用于控制不同权限的对象对目标对象的访问,但在 JavaScript 并不容易实现保护代理,因为我们无法判断谁访问了某个对象。
而虚拟代理是最常用的一种代理模式。
下面是一个图片预加载的代码,这里的代理起到了占位的作用。
<!DOCTYPE html> <html> <head> <title>图片预加载</title> </head> <body> </body> <script type="text/javascript"> var myImage=(function () { // body... var imgNode=document.createElement('img'); document.body.appendChild(imgNode); console.log(3) return { setSrc:function(src){ console.log(4) imgNode.src=src; } } })(); var proxyImage=(function(){ var img=new Image; img.onload=function(){ console.log(this.src) myImage.setSrc(this.src); } console.log(1) return { setSrc:function(src){ console.log(2) myImage.setSrc('./loading.jpg'); img.src=src; } } })(); proxyImage.setSrc("https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=716310665,173562528&fm=26&gp=0.jpg"); </script> </html>
图片预加载为什么要使用代理呢,是因为要遵循单一职责原则。
单一职责原则指的是,就一个类(通常也包括对象和函数等)而言,应该仅有一个引起它变化的原因。如果一个对象承担了多项职责,就意味着这个对象将变得巨大,引起它变化的原因可能会有多个。面向对象设计鼓励将行为分布到细粒度的对象之中,如果一个对象承担的职责过多,等于把这些职责耦合到了一起,这种耦合会导致脆弱和低内聚的设计。当变化发生时,设计可能会遭到意外的破坏。
代理和本体接口一致性。加载图片的myImage和proxyImage都使用的是setSrc接口。这样做有两个好处:
用户可以放心地请求代理,他只关心是否能得到想要的结果。
在任何使用本体的地方都可以替换成使用代理。
下面是代理模式下的求乘积,也是一个动态创建代理的例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>代理模式-求乘积</title> </head> <body></body> <script> //计算乘积的函数 var mult = function () { console.log("开始计算乘积"); var a = 1; for (let i = 0; i < arguments.length; i++) { a = a * arguments[i]; } return a; }; var plus = function () { var a = 0; console.log("开始计算加法"); for (var i = 0, l = arguments.length; i < l; i++) { a = a + arguments[i]; } return a; }; 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)); }; })(); var createProxyFactory = function (fn) { var cache = {}; return function () { var args = Array.prototype.join(arguments, ","); if (args in cache) { return cache[args]; } return (cache[args] = fn.apply(this, arguments)); }; }; var proxyPlus = createProxyFactory(plus); console.log(proxyMult(1, 2, 3, 4)); console.log(proxyMult(1, 2, 3, 4)); console.log(proxyPlus(1, 2, 3, 4)); console.log(proxyPlus(1, 2, 3, 4)); </script> </html>