设计模式-代理模式

举个例子,如果想请明星来办一场商业演出,你是无法直接联系到本人的,只能联系他的经纪人(明星本人的时间比较宝贵),经纪人会把商业演出的细节和报酬都谈好之后,再把合同交给明星签,经纪人就是代理。在程序中,代理可以看做是一个对象,这个对象是一个占位符

虚拟代理

在Web开发中,也许最大的开销就是网络请求。假设我们在做一个文件同步的功能,当我们选中一个 checkbox 的时候,它对应的文件就会被同步到另外一台备用服务器上面,如图所示

一般的做法是先获取到所有的checkbox,然后给他们绑定点击事件,并且在点击的同时往另一台服务器同步文件,这种做法有什么问题?如果用户在2s内选中了4个文件,需要向服务器发送4次HTTP请求,如此频繁的网络请求将会带来相当大的开销。

解决方案是,我们可以通过一个代理函数proxySynchronousFile来收集一段时间之内的请求,最后一次性发送给服务器

<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
var synchronousFile = function(id) {
  console.log('开始同步文件,id 为: ' + id);
};

var proxySynchronousFile = (function() {
  var cache = [], // 保存一段时间内需要同步的 ID
    timer; // 定时器
  return function(id) {
    cache.push(id);
    if (timer) { // 保证不会覆盖已经启动的定时器
      return;
    }
    timer = setTimeout(function() {
      synchronousFile(cache.join(',')); // 2 秒后向本体发送需要同步的 ID 集合
      clearTimeout(timer);
      timer = null;
      cache.length = 0;
    }, 2000);
  }
})();

var checkbox = document.getElementsByTagName('input');
for (var i = 0, c; c = checkbox[i++];) {
  c.onclick = function() {
    if (this.checked === true) {
      proxySynchronousFile(this.id);
    }
  }
};

缓存代理

缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参
数跟之前一致,则可以直接返回前面存储的运算结果

下面用计算乘积的例子演示如何使用缓存代理,实际开发中应该是开销较大的运算,这里仅作演示

// 计算乘积
var mult = function() {
  console.log('开始计算乘积');
  var a = 1;
  for (var i = 0, l = arguments.length; i < l; i++) {
    a = a * arguments[i];
  }
  return a;
};
// 代理工厂函数
var createProxyFactory = function(fn) {
  var cache = {};
  return function() {
    var args = Array.prototype.join.call(arguments, ','); // '1,2,3,4'
    if (args in cache) {
      return cache[args];
    }
    // {'1,2,3,4': 24}
    return cache[args] = fn.apply(this, arguments);
  }
};

var proxyMult = createProxyFactory(mult);

console.log(proxyMult(1, 2, 3, 4));
console.log(proxyMult(1, 2, 3, 4));

代理模式的变体种类非常多,比较常用的是虚拟代理和缓存代理,其他还有防火墙代理、远程代理、保护代理、智能引用代理和写时复制代理

posted @ 2021-10-07 15:05  wmui  阅读(25)  评论(0编辑  收藏  举报