JavaScript设计模式四(代理模式)

JavaScript设计模式四(代理模式)

代理模式的定义:

代理模式是为一个对象提供一个代用品或者占位符,以便对它的控制

代理模式的关键点在于,客户不关心请求的是代理还是本体,它只是想获得需要的东西。

我们还是通过例子来理解代理模式

代理模式例子

背景:小S需要最小L,但是小S很羞涩,刚好小C是小L和小S的朋友,小S委托小C送花给小L。

看看代码怎么实现吧,如果不经过小C,也就是不用代理模式

var Flower = function(){};

var xiaoS = {
    sendFlower: function(target){
        target.receiveFlower(new Flower());
    }
} 

var xiaoL = {
    receiveFlower: function(flower){
        console.log('receive flower: ' + flower);
    }
}

xiaoS.sendFlower(xiaoL);

如果小S勇敢一点,到这里也就结束了,大家也不用往下面继续看了,但是她怂了啊,还是需要小C来加把火

var Flower = function(){};

var xiaoS = {
    sendFlower: function(target){
        target.receiveFlower(new Flower());
    }
} 

var xiaoC = {
    receiveFlower: function(flower) {
        xiaoL.receiveFlower(flower);
    }
}

var xiaoL = {
    receiveFlower: function(flower){
        console.log('receive flower: ' + flower);
    }
}

xiaoS.sendFlower(xiaoC);

这里看起来本质上没啥区别,如果小L就是不喜欢小S,那么这里其实就是把简单的事情搞复杂了。但是小C真的就只有传递花的作用么?想想,小C是不是可以挑一下时间来送花呢?例如等小S心情好的时候再送花

var Flower = function(){};

var xiaoS = {
    sendFlower: function(target){
        target.receiveFlower(new Flower());
    }
} 

var xiaoC = {
    receiveFlower: function(flower) {
        xiaoL.listenGoodMood(function(){
            xiaoL.receiveFlower(flower);
        });
    }
}

var xiaoL = {
    receiveFlower: function(flower){
        console.log('receive flower: ' + flower);
    },
    listenGoodMood: function(fn) {
        setTimeout(function(){
            fn();   
        }, 1000);
    }
}

xiaoS.sendFlower(xiaoC);

代理模式分类

我们知道代理小C其实还可以做一些其他的事情,比如小C可以帮小L拒绝一些事情,例如追小L的送花的人没有宝马的,或者不帅的,这种请求在小C那里就直接被拦截掉了,这种模式就叫做保护代理。

我们上面看到有一个new Flower()的动作,但是这是一个很昂贵的操作,这个动作其实可以让代理去实现,代理会选择在小L心情好的时候再去new Flower(),这样给小S也节约了成本,这种形式就叫做虚拟代理。虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。

虚拟代理

虚拟代理可以实现图片的预加载、合并http请求、在惰性加载中也有应用

这里以图片预加载作为例子:

先看一下不在代理的情况

var myImage = (function(){
    var imgNode = document.createElement( 'img' );
    document.body.appendChild( imgNode );
    return { 
        setSrc: function( src ){ 
            imgNode.src = src; 
        } 
    } 
})();

myImage.setSrc( 'xxxxx.jpg' );

这个会有一个明显的问题,就是如果网络情况不好,在图片加载之前会有一段时间是空白的,

我们可以在图片加载前先弄一张loading.gif

var proxyImage = (function(){ 
    var img = new Image; 
    img.onload = function(){ 
        myImage.setSrc( this.src ); 
    };
    return { 
        setSrc: function( src ){ 
            myImage.setSrc( 'C://loading.gif' ); 
            img.src = src; 
        } 
    } 
})();

proxyImage.setSrc( 'XXXXX.jpg' );

如果大家多思考一下,可能会提出一个问题,这里的代理类,其实好像没什么必要,我不用代理也可以实现上面的需求

var MyImage = (function(){
    var imgNode = document.createElement('img');
    document.body.appChild(imgNode);
    var img = new Image;
    img.onload = function(){
        imgNode.src = img.src;
    };
    
    return {
        setSrc: function(src) {
            imgNode.src = 'c://loading.gif';
            img.src = src;
        }
    }
})();

MyImage.setSrc('xxx.jpg');

讲到这里就不得不说代理的意义了,先看我们上面提到的单一职责原则:

单一职责原则指的是,就一个类(通常也包括对象和函数等)而言,应该仅有一个引起它变化的原因

如果一个对象有多项责任,也就有多种导致它变换的原因,这也会导致程序的耦合。

我们利用代理,把给image设置节点和图片预加载两个功能分开了,他们的变换互相不影响,比如那一天我不需要图片预加载了,直接用以前设置节点的函数就可以了,不需要去重新修改函数,不是美滋滋么

缓存代理

缓存代理的应用也很多,例如计算乘积、ajax异步请求等

我们看一下计算乘积的例子

先看不加缓存代理:

var mult = function(){ 
    console.log( '开始计算乘积' ); 
    var a = 1; 
    for ( var i = 0, l = arguments.length; i < l; i++ ){
        a = a * arguments[i]; 
     } 
     return a; 
};

mult( 2, 3 ); 
mult( 2, 3, 4 );

// 输出:6 
// 输出:24

再看加了缓存代理:

var proxyMult = (function(){ 
    var cache = {}; 
    return function(){
        var args = Array.prototype.join.call( arguments, ',' ); 
        if ( args in cache ){ 
            return cache[ args ]; 
        } 
        return cache[ args ] = mult.apply( this, arguments ); 
    } 
})();

proxyMult( 1, 2, 3, 4 );
proxyMult( 1, 2, 3, 4 );

// 输出:24 // 输出:24
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,248评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,681评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,443评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,475评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,458评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,185评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,451评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,112评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,609评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,083评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,163评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,803评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,357评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,357评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,590评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,636评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,925评论 2 344

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,527评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,601评论 18 139
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,721评论 2 17
  • 1.定位为题: 调用定位时在target里设置两个属性:NSLocationAlwaysUsageDescript...
    HAKA阅读 1,118评论 0 0
  • 垦丁的夜空,满目繁星。北斗七星离我那么近。小车一转弯,天鹅座又清晰地出现在眼前。 "这都不算多,"兼当司机的民宿老...
    guitarclara阅读 196评论 0 0