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生成asp.net服务器控件的代码
Feb 04 Javascript
js将当前时间格式转换成时间搓(自写)
Sep 26 Javascript
js中reverse函数的用法详解
Dec 26 Javascript
浅析node.js中close事件
Nov 26 Javascript
以WordPress为例讲解jQuery美化页面Title的方法
May 23 Javascript
详解vue2父组件传递props异步数据到子组件的问题
Jun 29 Javascript
JS实现电商放大镜效果
Aug 24 Javascript
jquery引入外部CDN 加载失败则引入本地jq库
May 23 jQuery
vue v-model实现自定义样式多选与单选功能
Jul 05 Javascript
javascript原型链学习记录之继承实现方式分析
May 01 Javascript
Layui数据表格判断编辑输入的值,是否为我需要的类型详解
Oct 26 Javascript
javascript实现滚动条效果
Mar 24 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
DIY一个适配电脑声卡的动圈话筒放大器
2021/03/02 无线电
PHP 超链接 抓取实现代码
2009/06/29 PHP
php中时间轴开发(刚刚、5分钟前、昨天10:23等)
2011/10/03 PHP
PHP截取指定图片大小的方法
2014/12/10 PHP
Zend Framework校验器Zend_Validate用法详解
2016/12/09 PHP
YII框架关联查询操作示例
2019/04/29 PHP
新浪微博字数统计 textarea字数统计实现代码
2011/08/28 Javascript
js 实现css风格选择器(压缩后2KB)
2012/01/12 Javascript
js使浏览器窗口最大化实现代码(适用于IE)
2013/08/07 Javascript
Flexigrid在IE下不显示数据的处理的解决方法
2013/10/24 Javascript
浅谈使用MVC模式进行JavaScript程序开发
2015/11/10 Javascript
实例讲解JS中setTimeout()的用法
2016/01/28 Javascript
bootstrap fileinput 上传插件的基础使用
2017/02/17 Javascript
原生JS实现幻灯片
2017/02/22 Javascript
JQuery实现图片轮播效果
2017/05/08 jQuery
vue中路由参数传递可能会遇到的坑
2017/12/07 Javascript
使用Vue开发自己的Chrome扩展程序过程详解
2019/06/21 Javascript
JavaScript代码简化技巧实例解析
2020/09/09 Javascript
Python的类实例属性访问规则探讨
2015/01/30 Python
用Python的Django框架完成视频处理任务的教程
2015/04/02 Python
Python使用itertools模块实现排列组合功能示例
2018/07/02 Python
flask入门之表单的实现
2018/07/18 Python
Win8下python3.5.1安装教程
2020/07/29 Python
Python3中bytes类型转换为str类型
2018/09/27 Python
pandas读取csv文件,分隔符参数sep的实例
2018/12/12 Python
Python中使用__new__实现单例模式并解析
2019/06/25 Python
python实现比较类的两个instance(对象)是否相等的方法分析
2019/06/26 Python
Django model update的多种用法介绍
2020/03/28 Python
浅谈Python3实现两个矩形的交并比(IoU)
2020/01/18 Python
使用jupyter Nodebook查看函数或方法的参数以及使用情况
2020/04/14 Python
美国围栏公司:Walpole Outdoors
2019/11/19 全球购物
入党积极分子评语
2014/05/04 职场文书
2014年文艺部工作总结
2014/11/17 职场文书
2015年校务公开工作总结
2015/05/26 职场文书
JavaScript事件的委托(代理)的用法示例详解
2022/02/18 Javascript
如何让你的Nginx支持分布式追踪详解
2022/07/07 Servers