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 相关文章推荐
jQuery UI Autocomplete 1.8.16 中文输入修正代码
Apr 16 Javascript
jQuery ready()和onload的加载耗时分析
Sep 08 Javascript
基于Javascript倒计时效果
Dec 22 Javascript
JS实现图片高斯模糊切换效果的焦点图实例
Jan 21 Javascript
深入理解 JavaScript 中的 JSON
Apr 06 Javascript
让微信小程序支持ES6中Promise特性的方法详解
Jun 13 Javascript
移动端图片上传旋转、压缩问题的方法
Oct 16 Javascript
mpvue 单文件页面配置详解
Dec 02 Javascript
Vue实现按钮级权限方案
Nov 21 Javascript
详解vue-template-admin三级路由无法缓存的解决方案
Mar 10 Javascript
微信小程序保持session会话的方法
Mar 20 Javascript
vue实现点击出现操作弹出框的示例
Nov 05 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新手上路(九)
2006/10/09 PHP
php仿QQ验证码的实例分析
2013/07/01 PHP
php中get_object_vars()方法用法实例
2015/02/08 PHP
Codeigniter校验ip地址的方法
2015/03/21 PHP
php猴子选大王问题解决方法
2015/05/12 PHP
PHP使用strstr()函数获取指定字符串后所有字符的方法
2016/01/07 PHP
Windows平台PHP+IECapt实现网页批量截图并创建缩略图功能详解
2019/08/02 PHP
Swoole扩展的6种模式深入详解
2021/03/04 PHP
输入框的字数时时统计—关于 onpropertychange 和 oninput 使用
2011/10/21 Javascript
用js实现小球的自由移动代码
2013/04/22 Javascript
一个判断抢购时间是否到达的简单的js函数
2014/06/23 Javascript
escape函数解决js中ajax传递中文出现乱码问题
2014/10/30 Javascript
jquery实现可拖拽弹出层特效
2015/01/04 Javascript
JavaScript中匿名函数用法实例
2015/03/23 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
每天一篇javascript学习小结(Function对象)
2015/11/16 Javascript
jquery.validate提示错误信息位置方法
2016/01/22 Javascript
bootstrap switch开关组件使用方法详解
2017/08/22 Javascript
vue-cli整合vuex的时候,修改actions和mutations,实现热部署的方法
2018/09/19 Javascript
VuePress 中如何增加用户登录功能
2019/11/29 Javascript
react ant Design手动设置表单的值操作
2020/10/31 Javascript
[58:57]2018DOTA2亚洲邀请赛3月29日小组赛B组 Effect VS VGJ.T
2018/03/30 DOTA
老生常谈Python之装饰器、迭代器和生成器
2017/07/26 Python
Tensorflow实现卷积神经网络用于人脸关键点识别
2018/03/05 Python
Python检测网络延迟的代码
2018/05/15 Python
Python实现基于KNN算法的笔迹识别功能详解
2018/07/09 Python
python单线程文件传输的实例(C/S)
2019/02/13 Python
Python3.5装饰器典型案例分析
2019/04/30 Python
python使用Geany编辑器配置方法
2020/02/21 Python
CSS3动画特效在活动页中的应用
2020/01/21 HTML / CSS
HTML5 placeholder属性详解
2016/06/22 HTML / CSS
工会主席岗位责任制
2014/02/11 职场文书
幼儿园小班评语
2014/04/18 职场文书
党的群众路线教育实践活动对照检查材料思想汇报
2014/09/19 职场文书
预防职务犯罪警示教育心得体会
2016/01/15 职场文书
Mysql 设置boolean类型的操作
2021/06/04 MySQL