学习《JavaScript设计模式与开发实践》- 代理模式

写在前面

最近在学习《JavaScript设计模式与开发实践》一书,每看完一个模块,会写一篇文档来做为笔记,如果你也在学习JS设计模式,欢迎留言交流。

原理

代理模式,顾名思义就是给一样东西添加一层代理,代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身
对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之
后,再把请求转交给本体对象。

另一种情况是对象需要做的事情过多,违反了单一职能原则,这时就需要考虑创建其代理对象来进行功能的拆分。

一,保护代理

假设小明给mm表白,通过一个朋友,送一束花,但是送的时机需要朋友确认mm心情,送的动作也需要朋友完成,不然花就会浪费掉,这里的朋友就是一个保护代理。

我们先来编写小明的对象

var Flower = function(){};
var xiaoming = {
 sendFlower: function( target){
 var flower = new Flower();
 target.receiveFlower( flower );
 }
};
xiaoming.sendFlower( B ); 
复制代码

然后再编写代理对象和MM

var proxy = {
 receiveFlower: function( flower ){
 MM.listenGoodMood(function(){ // 监听 MM 的好心情
 var flower = new Flower(); // 延迟创建 flower 对象
 MM.receiveFlower( flower );
 });
 }
}; 
var MM = {
 receiveFlower: function( flower ){
 console.log( '收到花 ' + flower );
 },
 
 // 假设 10 秒之后 A 的心情变好
 listenGoodMood: function( fn ){
 setTimeout(function(){ 
        fn();
 }, 10000 );
 }
};
复制代码

最后调用xiaoming.sendFlower( proxy )就可以送出花了

二,虚拟代理

虚拟代理一般是给目标对象设置一层代理,然后通过代理完成一部分操作,用来节约资源或者方便使用。

1,图片预加载

在 Web 开发中,图片预加载是一种常用的技术,如果直接给某个 img 标签节点设置 src 属性,
由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张
loading 图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到 img 节点里,这种
场景就很适合使用虚拟代理。

我们先编写创建节点的代码

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' ); 

复制代码

2,合并http请求

假设页面中dom的每一次点击都需要发送一次http请求,这会非常消耗性能,于是,我们可以通过代理将一段时间内的http请求收集起来,然后统一发送。

首先编写发送请求的组件


var checkbox = document.getElementsByTagName( 'input' );
    for ( var i = 0, c; c = checkbox[ i++ ]; ){
         c.onclick = function(){
         if ( this.checked === true ){
             proxySynchronousFile( this.id );
         }
     }
}; 
复制代码

编写统一发送的代理

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( ',' ) ); // 2 秒后向本体发送需要同步的 ID 集合
             clearTimeout( timer ); // 清空定时器
             timer = null;
             cache.length = 0; // 清空 ID 集合
         }, 2000 );
     }
})();
复制代码

3,惰性加载

假如我们想要在页面加载一个模态框,但是如果用户不需要的话,直接加载会耗费一定的资源。所以我们会在用户使用其功能时加载模态框,但是为了不影响使用,我们需要在加载出真正模态框之前提供一个代理对象给用户使用。当模态框真正加载出来后才去执行用户点击的逻辑。

三,缓存代理

缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参
数跟之前一致,则可以直接返回前面存储的运算结果。

1,计算乘积

//先创建一个用于求乘积的函数:
       var mul = function(x,y){
           return x*y;
       }
复制代码

现在加入缓存函数

       var mulProxy = function(){
           var ache = [];
            return function(x,y){
                exitArr = ache.filter(item => item.x == x && item.y == y);
            if(exitArr.length>0){
                console.log('通过缓存得到');
                return exitArr[0].result;
            }else{
                console.log('通过计算得到');
                var result = mul(x,y);
                ache.push({
                    x,
                    y,
                    result
                });
                return result;
            }
           }
       }
       var mulProxyFunc = mulProxy();
复制代码

2,高阶函数创建动态代理

/**************** 计算乘积 *****************/
var mult = function(){
 var a = 1;
 for ( var i = 0, l = arguments.length; i < l; i++ ){
 a = a * arguments[i];
 }
 return a;
};
/**************** 计算加和 *****************/
var plus = function(){
 var a = 0;
 for ( var i = 0, l = arguments.length; i < l; i++ ){
 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
复制代码

最后

本文介绍了JS设计模式中的代理模式的三种情况,如果你觉得本文对你有用的话,不妨点个赞再走呀…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享