JavaScript设计模式之代理模式详解


Posted in Javascript onJune 09, 2017

代理模式是非常常见的模式,比如我们使用的VPN工具,明星的经纪人,都是代理模式的例子。但是,有人会疑问,明明可以直接访问对象,为什么中间还要加一个壳呢?这也就说到了代理模式的好处。在我看来,代理模式最大的好处,就是在不动原有对象的同时,可以给原有对象增加一些新的特性或者行为。

/**
 * 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));

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 检测浏览器类型和版本的代码
Sep 15 Javascript
js取两个数组的交集|差集|并集|补集|去重示例代码
Aug 07 Javascript
jQuery+easyui中的combobox实现下拉框特效
Feb 27 Javascript
jquery使用animate方法实现控制元素移动
Mar 27 Javascript
JavaScript中length属性的使用方法
Jun 05 Javascript
JS实现选择TextArea内文本的方法
Aug 03 Javascript
JavaScript toUpperCase()方法使用详解
Aug 26 Javascript
jQuery实现滚动条滚动到子元素位置(方便定位)
Jan 08 Javascript
Django使用多数据库的方法
Sep 06 Javascript
js精确的加减乘除实例
Nov 14 Javascript
详解用async/await来处理异步
Aug 28 Javascript
maptalks+three.js+vue webpack实现二维地图上贴三维模型操作
Aug 10 Javascript
vue.js+Echarts开发图表放大缩小功能实例
Jun 09 #Javascript
vue2 中如何实现动态表单增删改查实例
Jun 09 #Javascript
JS创建Tag标签的方法详解
Jun 09 #Javascript
JavaWeb表单及时验证功能在输入后立即验证(含用户类型,性别,爱好...的验证)
Jun 09 #Javascript
JS实现的随机排序功能算法示例
Jun 09 #Javascript
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
Jun 09 #jQuery
JQuery.dataTables表格插件添加跳转到指定页
Jun 09 #jQuery
You might like
php array_flip() 删除数组重复元素
2009/01/14 PHP
ThinkPHP模板标签eq if 中区分0,null,false的方法
2017/03/24 PHP
qq悬浮代码(兼容各个浏览器)
2014/01/29 Javascript
jQuery检测输入的字符串包含的中英文的数量
2015/04/17 Javascript
在jQuery中处理XML数据的大致方法
2015/08/14 Javascript
JavaScript 模块的循环加载实现方法
2015/12/13 Javascript
js跨浏览器的事件侦听器和事件对象的使用方法
2015/12/17 Javascript
jQuery实现点击查看大图并以弹框的形式居中
2016/08/08 Javascript
vue.js开发环境搭建教程
2017/05/04 Javascript
Angular中$state.go页面跳转并传递参数的方法
2017/05/09 Javascript
Angular(5.2-&gt;6.1)升级小结
2018/12/27 Javascript
详解小程序input框失焦事件在提交事件前的处理
2019/05/05 Javascript
Vue 设置axios请求格式为form-data的操作步骤
2019/10/29 Javascript
[03:57]DOTA2英雄梦之声_第03期_幻影刺客
2014/06/21 DOTA
[42:06]2019国际邀请赛全明星赛 8.23
2019/09/05 DOTA
python连接MySQL、MongoDB、Redis、memcache等数据库的方法
2013/11/15 Python
详解Python中用于计算指数的exp()方法
2015/05/14 Python
python如何通过twisted实现数据库异步插入
2018/03/20 Python
详谈pandas中agg函数和apply函数的区别
2018/04/20 Python
解决Python print 输出文本显示 gbk 编码错误问题
2018/07/13 Python
Python----数据预处理代码实例
2019/03/20 Python
python中对数据进行各种排序的方法
2019/07/02 Python
Python中*args和**kwargs的区别详解
2019/09/17 Python
Python 文件数据读写的具体实现
2020/01/24 Python
python可以用哪些数据库
2020/06/22 Python
德国购买健身器材:AsVIVA
2017/08/09 全球购物
GE设备配件:GE Appliance Parts(家电零件、配件和滤水器)
2018/11/28 全球购物
英国领先的互联网葡萄酒礼品商:Vintage Wine & Port
2019/05/24 全球购物
宝信软件JAVA工程师面试经历
2012/08/19 面试题
户外宣传策划方案
2014/05/25 职场文书
九一八事变演讲稿
2014/09/05 职场文书
教师党员自我评议不足范文
2014/10/19 职场文书
2016秋季小学开学寄语
2015/12/03 职场文书
领导干部学习三严三实心得体会
2016/01/05 职场文书
导游词之镜泊湖
2019/12/09 职场文书
手把手教你怎么用Python实现zip文件密码的破解
2021/05/27 Python