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 相关文章推荐
图片上传即时显示缩略图的js代码
May 27 Javascript
jQuery 常见开发使用技巧总结
Dec 26 Javascript
javascript开发技术大全-第3章 js数据类型
Jul 03 Javascript
JavaScript事件委托用法分析
Jan 24 Javascript
javascript实现控制浏览器全屏
Mar 30 Javascript
AngularJS中如何使用$http对MongoLab数据表进行增删改查
Jan 23 Javascript
微信小程序 slider 详解及实例代码
Jan 10 Javascript
easyui下拉框动态级联加载的示例代码
Nov 29 Javascript
React SSR样式及SEO的实践
Oct 22 Javascript
JavaScript中callee和caller的区别与用法实例分析
Jun 28 Javascript
jquery制作的移动端购物车效果完整示例
Feb 24 jQuery
vue倒计时刷新页面不会从头开始的解决方法
Mar 03 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
10个实用的PHP代码片段
2011/09/02 PHP
PHP查询数据库中满足条件的记录条数(两种实现方法)
2013/01/29 PHP
谈谈关于php的优点与缺点
2013/04/11 PHP
PHP数字和字符串ID互转函数(类似优酷ID)
2014/06/30 PHP
基于Swoole实现PHP与websocket聊天室
2016/08/03 PHP
js下将阿拉伯数字每三位一逗号分隔(如:15000000转化为15,000,000)
2014/06/02 Javascript
微信小程序 WXML、WXSS 和JS介绍及详解
2016/10/08 Javascript
微信小程序 加载 app-service.js 错误解决方法
2016/10/12 Javascript
JavaScript制作简单的框选图表
2017/05/15 Javascript
JavaScript调试之console.log调试的一个小技巧分享
2017/08/07 Javascript
get  post jsonp三种数据交互形式实例详解
2017/08/25 Javascript
Vue2.0用户权限控制解决方案的示例
2018/02/10 Javascript
JavaScript 点击触发复制功能实例详解
2018/11/02 Javascript
详解微信小程序回到顶部的两种方式
2019/05/09 Javascript
nodejs搭建本地服务器并访问文件操作示例
2019/05/11 NodeJs
微信小程序 组件的外部样式externalClasses使用详解
2019/09/06 Javascript
vue+vant使用图片预览功能ImagePreview的问题解决
2020/04/10 Javascript
element-ui 实现响应式导航栏的示例代码
2020/05/08 Javascript
使用Python的Bottle框架写一个简单的服务接口的示例
2015/08/25 Python
Python socket实现的简单通信功能示例
2018/08/21 Python
python 列表递归求和、计数、求最大元素的实例
2018/11/28 Python
Python使用reportlab模块生成PDF格式的文档
2019/03/11 Python
基于Python解密仿射密码
2019/10/21 Python
Django实现CAS+OAuth2的方法示例
2019/10/30 Python
Python+Appium实现自动化测试的使用步骤
2020/03/24 Python
使用Python解析Chrome浏览器书签的示例
2020/11/13 Python
html5视频媒体标签video的使用方法及完整参数说明详解
2019/09/27 HTML / CSS
NBA欧洲商店(英国):NBA Europe Store UK
2018/07/27 全球购物
阿姆斯特丹城市卡:Amsterdam Pass
2019/12/01 全球购物
英语翻译系毕业生求职信
2013/09/29 职场文书
餐饮业的创业计划书范文
2013/12/26 职场文书
小孩百日宴答谢词
2014/01/15 职场文书
运动会通讯稿100字
2014/01/31 职场文书
社区公民道德宣传日活动总结
2015/03/23 职场文书
机关干部正风肃纪心得体会
2016/01/15 职场文书
穷人该怎么创业?谨记以下几点
2019/07/11 职场文书