JavaScript设计模式之代理模式详解
网络 2017-06-13 1370
代理模式是非常常见的模式,比如我们使用的VPN工具,明星的经纪人,都是代理模式的例子。但是,有人会疑问,明明可以直接访问对象,为什么中间还要加一个壳呢?这也就说到了代理模式的好处。在我看来,代理模式最大的好处,就是在不动原有对象的同时,可以给原有对象增加一些新的特性或者行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | /** * pre:代理模式 * 小明追求A,B是A的好朋友,小明比较腼腆,不好意思直接将花交给A, * 于是小明将花交给B,再由B交给A. */ //----------- 示例1 --------- // 不使用代理 var Flower = function() {}; var xiaoming = { sendFlower: function(target) { var flower = new Flower(); target.receiveFlower(flower); } }; var A = { receiveFlower: function(flower) { console.log("收到花:" + flower); } }; xiaoming.sendFlower(A); // ----------- 示例2 -------------- // 使用代理1 var Flower = function() {}; var xiaoming = { sendFlower: function(target) { var flower = new Flower(); B.receiveFlower(flower); } }; var B = { receiveFlower: function(flower) { A.receiveFlower(flower); } }; var A = { receiveFlower: function(flower) { console.log("收到花:" + flower); } }; xiaoming.sendFlower(B); //------------- 示例3 --------------- /* * 使用代理2 * 从示例1和示例2,看不出使用代理有什么用处,B只不过是从中间转手了一次。 * 接下来,我们想一下。给喜欢的人送花,怎样才能提高成功率呢? * 我们都知道,人有心情好和心情差的时候,当美女心情好的时候,送花成功的概率自然要大些。 * 于是,我们将代理升级,监听美女的心情,心情好的时候再给她送花。 * 为了演示,我们假设2秒后,A的心情变好。 */ var Flower = function() {}; var xiaoming = { sendFlower: function(target) { var flower = new Flower(); B.receiveFlower(flower); } }; var B = { receiveFlower: function(flower) { A.listenGoodMood(function() { A.receiveFlower(flower); }); } }; var A = { receiveFlower: function(flower) { console.log("收到花:" + flower); }, listenGoodMood: function(fn) { setTimeout(function() { fn.apply(this, arguments); }, 2000); } }; xiaoming.sendFlower(B); // ---------- 示例4 --------------- /* * 【代理模式用处】:虚拟代理 * 这里以加载图片为例,我们都知道当网络不畅以及图片过大时,图片加载都比较慢, * 为了更好的用户体验,我们都会在原图片未加载完成前,加上loading图片。 * */ //--4 _01未使用代理-- var myImage = (function() { var imgNode = document.createElement("img"); document.body.appendChild(imgNode); return { setSrc: function(src) { this.imgNode.src = src; } } })(); myImage.setSrc("xxx"); //--4_02使用代理-- var proxyMyImage = (function() { var img = new Image(); img.onload = function() { myImage.setSrc(this.src); }; return { setSrc: function(src) { myImage.setSrc("loading.jpg"); img.src = src; } } })(); proxyMyImage.setSrc("xxx"); /* * [注]:这里可以看到代理模式的好处:在不改变原有接口的同时,可以为系统添加新的行为。 */ //--------- 示例5--------------- /* * 【代理模式用处】:合并http请求 * 这里以选择文件同步为例。 * 以往用户同步文件,在用户选中的时候就触发,这种方法做到了实时性,但无疑增加了网络的开销。 * 实际在使用的过程中,往往并不需要立刻就同步。 * 以下通过代理模式,将在用户选中文件2秒后进行同步请求。 * */ // --- 包含一段html代码,请自行添加到一个文件中 ------ <html> <body> <button id="input">点我上传</button> <input type="checkbox" id="1"></input>1 <input type="checkbox" id="2"></input>2 <input type="checkbox" id="3"></input>3 <input type="checkbox" id="4"></input>4 <input type="checkbox" id="5"></input>5 <input type="checkbox" id="6"></input>6 <input type="checkbox" id="7"></input>7 <input type="checkbox" id="8"></input>8 <input type="checkbox" id="9"></input>9 </body> </html> // -- 上传文件 -- var synchronizeFile = function(id) { console.log("开始同步文件:" + id); }; var proxySynchronizeFiles = (function() { var fileCache = [], timer; return function(id) { fileCache.push(id); if(timer) { return; } timer = setTimeout(function() { synchronizeFile(fileCache.join(",")); clearTimeout(timer); timer = null; checkArr.length = 0; }, 2000); } })(); var checkArr = document.getElementsByTagName("input"); for(var i = 0, c; c = checkArr[i++];) { c.onclick = function() { if(this.checked == true) { proxySynchronizeFiles(this.id); } } } // ------------ 示例6 ----------------- /* * 【代理模式用处】:缓存代理 * 以计算器为例,比如计算某些数的乘积,当参数重复时,我们希望不用重复计算,直接返回结果。 * 以下用到代理模式做缓存。 */ var mult = function() { if(!arguments) { console.log("请输入参数"); return; } var a = 1; for(var i = 0, b; b = arguments[i++];) { a = a * b; } return a; }; var proxyMult = (function() { var cache = {}; return function() { var str = Array.prototype.join.call(arguments, ","); if(str in cache) { console.log("重复return."); return cache[str]; } return cache[str] = mult.apply(this, arguments); } })(); console.log(proxyMult(2, 3, 4)); console.log(proxyMult(2, 3, 4)); //------------ 示例7 -------------- /* * 缓存代理升级 - 通用版计算 * */ var mult = function() { if(!arguments) { return; } var t = 1; for(var i = 0, a; a = arguments[i++];) { t = t * a; } return t; }; var plus = function() { if(!arguments) { return; } var t = 0; for(var a of arguments) { t += a; } return t; }; var createProxyCaculate = function(fn) { var cache = {}; return function() { var str = Array.prototype.join.call(arguments, ","); if(str in cache) { console.log("重复return" + str); return cache[str]; } return cache[str] = fn.apply(this, arguments); } }; var proxyMult = createProxyCaculate(mult); var proxyPlus = createProxyCaculate(plus); console.log(proxyMult(2, 3, 4)); console.log(proxyMult(2, 3, 4)); |
以上就是本文的全部内容,希望对大家的学习有所帮助
上一篇:讨论CSS中的各类居中方式
下一篇:JS创建Tag标签的方法详解