一、简单的代理模式:

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、使用简单的代理模式:小明通过B给女神送花

var Flower = function() {}
var xiaoming = {
sendFlower: function( target ){
var flower = new Flower();
target.receiveFlower( flower );
}
};
var A = {
receiveFlower: function( flower ){
console.log( '收到花 ' , flower );
}
};
var B = {
receiveFlower: function( flower ){
A.receiveFlower(flower)
}
}
xiaoming.sendFlower( B );

二、保护代理和虚拟代理

虽然这只是个虚拟的例子,但我们可以从中找到两种代理模式的身影。代理 B 可以帮助 A 过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理 B 处被拒绝掉。这种代理叫作保护代理。A 和 B 一个充当白脸,一个充当黑脸。白脸 A 继续保持 良好的女神形象,不希望直接拒绝任何人,于是找了黑脸 B 来控制对 A 的访问。

另外,假设现实中的花价格不菲,导致在程序世界里,new Flower 也是一个代价昂贵的操作, 那么我们可以把 new Flower 的操作交给代理 B 去执行,代理 B 会选择在 A 心情好时再执行 new Flower,这是代理模式的另一种形式,叫作虚拟代理。虚拟代理把一些开销很大的对象,延迟到 真正需要它的时候才去创建。

三、虚拟代理实现图片预加载

var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ){
imgNode.src = src;
}
}
})();
myImage.setSrc('http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg');
普通方式下,我们把网速调至 5KB/s,然后通过 MyImage.setSrc 给该 img 节点设置 src,可以看到,在图片被加载好之前,页面中有一段长长的空白时间。
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ){
imgNode.src = src;
}
}
})();
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage.setSrc(this.src);
}
return {
setSrc: function( src ){
myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
img.src = src;
}
}
})();
proxyImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );
代理模式改造后,现在开始引入代理对象 proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的菊花图 loading.gif, 来提示用户图片正在加载。proxyImage 控制了客户对 MyImage 的访问,并且在此过程中加入一些额外的操作,比如在真正的图片加载好之前,先把 img 节点的 src 设置为 一张本地的 loading 图片。

四、虚拟代理合并HTTP请求

<body>
<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>
给这些 checkbox 绑定点击事件,并且在点击的同时往另一台服务器同步文件:当我们选中3个checkbox 的时候,依次往服务器发送了3次同步文件的请求。而点击一个checkbox并不是很复杂的操作。可以预见,如此频繁的网络请求将会带来相当大的开销。
var synchronousFile = function( id ){
console.log( '开始同步文件,id 为: ' + id );
};
var checkbox = document.getElementsByTagName( 'input' );
for ( var i = 0, c; c = checkbox[ i++ ]; ){
c.onclick = function(){
if ( this.checked === true ){
synchronousFile( this.id );
}
}
};

解决方案是,我们可以通过一个代理函数 proxySynchronousFile 来收集一段时间之内的请求, 最后一次性发送给服务器。比如我们等待 2 秒之后才把这 2 秒之内需要同步的文件 ID 打包发给 服务器,如果不是对实时性要求非常高的系统,2 秒的延迟不会带来太大副作用,却能大大减轻 服务器的压力。:

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( ',' ) );
clearTimeout( timer ); // 清空定时器 timer = null;
cache.length = 0; // 清空 ID 集合
}, 2000);
}
// 2 秒后向本体发送需要同步的 ID 集合
})();
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(){
var a = 1;
for ( i = 0, l = arguments.length; i < l; i++ ){
var a = a* arguments[i];
}
return a;
}; /**************** 计算加和 *****************/
var plus = function(){
var a = 1;
for ( i = 0, l = arguments.length; i < l; i++ ){
var a = a + arguments[i];
}
return a;
}; /**************** 创建缓存代理的工厂 *****************/
var createProxyFactory = function( fn ){
var cache = {};
return function(){
var args = Array.prototype.join.call( arguments, ',' );
if ( args in cache ){
return cache[ args ];
}
return cache[ args ] = fn.apply( this, arguments );
}
}; var proxyMult = createProxyFactory( mult ),
proxyPlus = createProxyFactory( plus ); alert ( proxyMult( 1, 2, 3, 4 ) ); // 输出:24
alert ( proxyMult( 1, 2, 3, 4 ) ); // 输出:24
alert ( proxyPlus( 1, 2, 3, 4 ) ); // 输出:10
alert ( proxyPlus( 1, 2, 3, 4 ) ); // 输出:10

JavaScript设计模式(代理模式)的更多相关文章

  1. JavaScript设计模式 - 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 代理模式的用处(个人理解):为了保障当前对象的单一职责(相对独立性),而需要创建另一个对象来处理调用当前对象之前的一些逻辑以提高代码的效 ...

  2. 读书笔记之 - javascript 设计模式 - 代理模式

    代理(proxy)是一个对象,它可以用来控制对另一对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替本体被实例化,并使其可被远程访 ...

  3. javascript设计模式——代理模式

    前面的话 代理模式是为一个对象提供一个占位符,以便控制对它的访问. 代理模式是一种非常有意义的模式,在生活中可以找到很多代理模式的场景.比如,明星都有经纪人作为代理.如果想请明星来办一场商业演出,只能 ...

  4. JavaScript设计模式—代理模式

    代理模式介绍 使用者无权访问目标对象,中间加代理,通过代理做授权和控制 代理(proxy)是一个对象,它可以用来控制对另外一个对象的访问: 代理对象和本体对象实现了同样的接口,并且会把任何方法调用传递 ...

  5. 9. 星际争霸之php设计模式--代理模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  6. C++设计模式——代理模式

    前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就溜走了,现在上班的时候,偶尔还会怀念大学时,大家在一起玩游戏的时光.大学喜欢玩游戏,但是可悲的校园网,速度能把人逼疯了:还好,后来搞了一个 ...

  7. PHP设计模式-代理模式

    概念理解: 代理模式,是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理对象取代,代理对象位于客户端和真实程序之间,指针有一个可被多个目标利用的钩子. 参与者: client(参与者) ...

  8. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  9. 浅谈Python设计模式 - 代理模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...

  10. Java 之 设计模式——代理模式

    设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...

随机推荐

  1. 使用 .gitignore 忽略 Git 仓库中的文件

    .gitignore 在Git中,很多时候你只想将代码提交到仓库,而不是将当前文件目录下的文件全部提交到Git仓库中,例如在MacOS系统下面的.DS_Store文件,或者是Xocde的操作记录,又或 ...

  2. Angular6 CodeMirror在线编辑sql 智能提示

    1. 安装ng2-codemirror包.codemirror包 npm install ng2-codemirror -- save npm install codemirror -- save 2 ...

  3. Redis 的主从同步(复制)

    Redis 的主从同步(复制) Redis 的主从同步(复制) 什么是主从同步(复制) 假设有两个 redis 实例 ⇒ A 和 B B 实例的内容与 A 实例的内容保持同步 那么称 A 实例是主数据 ...

  4. [Vjudge][POJ][Tony100K]搜索基础练习 - 全题解

    目录 POJ 1426 POJ 1321 POJ 2718 POJ 3414 POJ 1416 POJ 2362 POJ 3126 POJ 3009 个人整了一些搜索的简单题目,大家可以clone来练 ...

  5. java实现有道翻译爬虫

    我的博文地址 https://www.cnblogs.com/lingdurebing/p/11618902.html 使用的库 1.commons-codec 主要是为了加密,可以直接用java原生 ...

  6. LAMP模拟搭建wordpress,phpmyadmin环境

    1.安装需要的环境,centos7的mysql叫mariadb,所有的配置文件默认就可以 [root@test ~]# yum install httpd php mariadb mariadb-se ...

  7. more,less,head,tail

    当用cat,tac命令查看文件时,文件的所有内容都会被刷出来,因为缓存有限,被刷过去的内容可能就留不住了.用cat查看个小文件还可以,查看大文件时就用到下面的命令. more (选项)(参数)    ...

  8. 用深度学习做命名实体识别(六)-BERT介绍

    什么是BERT? BERT,全称是Bidirectional Encoder Representations from Transformers.可以理解为一种以Transformers为主要框架的双 ...

  9. 从零开始的vue学习笔记(二)

    数据与方法 当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中.data的数据和视图同步更新. 实例创建后添加一个新的属性,对这个属性的的改动将不会触发任何 ...

  10. [UWP] 自定义一个ItemsPanel

    在做游民星空的搜索页面的时候,需要展示搜索热点词,返回的是一个string数组的形式,然后以一种错落的方式显示,每一个Item的大小都和热点词长度一致,然后一行放不下之后就换行,描述的不太直观,直接看 ...