上一篇<<JavaScript 设计模式之工厂模式>>javascript
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 代理模式的用处(我的理解): 为了保障当前对象的单一职责(相对独立性), 而须要建立另外一个对象来处理调用当前对象以前的一些逻辑以提升代码的效率、状态判断等。 代理模式中最经常使用的是虚拟代理和缓存代理
在现实生活中,能够找到不少代理模式使用的场景。明星都有经纪人做为代理。若是请明星来演出,就要先同他的经纪人沟通,谈好相应的细节与报酬。再交给明星。
需求:公司(Company)经过经纪人(agent)找明星(start)开演唱会java
//演唱会 var Concert = function(){} //公司 var Company = { askforconcert: function(target){ var concert = new Concert(); target.openconcert(concert ) } } //明星 var star = { openconcert: function(concert){ console.log("明星赞成开一场演唱会") } } //经纪人代理 var agent = { openconcert: function(concert){ star.openconcert(concert) } } //执行 Company.askforconcert(agent); //=>明星赞成开一场演唱会 /*这样 company直接把请求发给agent,agent再转给star,这样就完成了一个简单的代理模式 (compan=>agent=>star)*/ //经济人能够帮助 明星过滤掉一些请求,好比 钱不够多或者场地不够好,这种请求能够直接在经纪人出被过滤拒绝掉。 //这种代理就叫作保护代理。 //由经纪人Agent来控制对明星star的访问。
- 若是A 经过 B 送花给C,咱们能够在A的时候new 一个 flower传递给代理B,再由B决定何时或者是否要再转交个最终的target C。new Flower这个操做能够交给B,B决定能够送花给C的时候再由B作 new Flower的操做。这种模式就叫作虚拟代理。虚拟代理把一些开销很大的对象,延迟到真正须要它的时候才去建立ajax
var Flower = function(){ this.price = 150 } var a = { sendflower: function(target){ var flower = new Flower() target.receiveFlower(flower ) } } var b = { receiveFlower: function(flower){ if(flower.price < 100){ console.log("太便宜了,女神表示一脸嫌弃") return false }else{ c.receiveFlower(flower) } }, } var c = { receiveFlower: function(){ console.log("接受了鲜花") } }
//不使用代理 var preLoadImage = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode) var img = new Image(); img.onload = function(){ imgNode.src = img.src } return { setSrc: function(src){ imgNode.src = "loading.gif"; img.src = src; } } })()
//使用代理模式的实现方式 var image = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode); return { setSrc: function(src){ imgNode.src = src; } } })() //代理 var proxyImage = (function(){ var img = new Image(); img.onload = function(){ // 图片加载完成,正式加载图片 image.setSrc = img.src; } return { setSrc: function(src){ image.setSrc = "loading.gif"; img.src = src; } } })
单一职责原则
单一职责指的是,对一个类而言,应该仅有一个引发他变化的缘由。若是一个对象承担了多个原则,就意味着这个对象将变得巨大,引发他变化的缘由可能也会有多个。面向对象设计鼓励将行为分不到细粒度的对象之中,若是一个对象承担的职责过多,等于把这些值得耦合到了一块儿,这种耦合会致使脆弱和低内聚的设计。当变化发生时,设计可能会遭到意外的破坏。(书中93页)后端
preLoadImage方法,承担了添加img标签,还有预加载两个功能,代码耦合到了一块儿,当我修改添加标签时,可能会影响到另外一部分功能。设计模式
而用代理方法重构后,image方法只负责建立标签,设置src,预加载功能交给了proxyImage,解除了耦合的代码,两个功能互不干扰。数组
var syncFile = function(id){ $.ajax({ data: { id: id } })... } //绑定事件 for(var i = 0;i<fileObjArr.length;i++){ fileObjArr[i].onclick = function(){ if(this.checked === true){ syncFile(this.id) } } }
这里有个很严重的问题,每点一个都会发送一个ajax请求,性能上,这是一个很大的开销缓存
需求: 文件同步穿,选中的文件会被上传到服务器上,解决方法,咱们能够 经过一个代理函数,来收集一段时间内的请求,将请求的参数缓存起来,与后端人员协商将选中的id做为一个数组传到后台保存。服务器
var syncFile = function(ids){ $.ajax({ data: { id: ids } })... } var proxyFile = (function(){ var cache = [], timer = null; return function(id){ cache.push(id); if(timer){ return } timer = setTimeout(function(){ syncFile(cache.join(",")) clearTimeout(timer); timer = null; cache = []; },2000) } })() //绑定事件 for(var i = 0;i<fileObjArr.length;i++){ fileObjArr[i].onclick = function(){ if(this.checked === true){ proxyFile(id) } } }
这样,有选中操做的话,不会频繁触发请求。app
缓存代理能够为一些开销大的运算结果提供暂时的存储,在下次运算时,若是传递进来的参数跟以前一致, 则能够返回前面的运算结果。 示例: 为乘法、加法等建立缓存代理
// 计算乘积 var mult = function(){ var a = 1; for( var i = 0, l = arguments.length; i < l; i++){ a = a * arguments[i]; } return a; }; // 计算加和 var plus = function () { var a = 0; for( var i = 0, l = arguments.length; i < l; i++ ){ a += arguments[i]; } return a; }; // 建立缓存代理的工厂 var createProxyFactory = function( fn ){ var cache = {}; // 缓存 - 存放参数和计算后的值 return function(){ var args = Array.prototype.join.call(arguments, "-"); if( args in cache ){ // 判断出入的参数是否被计算过 console.log( "使用缓存代理" ); return cache[args]; } return cache[args] = fn.apply( this, arguments ); } }; // 建立代理 var proxyMult = createProxyFactory( mult ), proxyPlus = createProxyFactory( plus ); console.log( proxyMult( 1, 2, 3, 4 ) ); // 输出: 24 console.log( proxyMult( 1, 2, 3, 4 ) ); // 输出: 缓存代理 24 console.log( proxyPlus( 1, 2, 3, 4 ) ); // 输出: 10 console.log( proxyPlus( 1, 2, 3, 4 ) ); // 输出: 缓存代理 10