第6章代理模式

第6章代理模式

6.1 第一個例子--小明追MM的故事

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

引入代理B

var Flower = function () {};

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

var B = {
    receiveFlower:function(flower){
        A.receiveFlower(flower)
    }
}
var A = {
    receiveFlower:function(flower){
        console.log('收到花'+flower);
    }
}

xiaoming.sendFlower(B);

B會監(jiān)聽A的心情變化

var Flower = function () {};

var xiaoming = {
    sendFlower : function(target){
        var flower = new Flower();
        target.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();
        },3000);

    }
}

xiaoming.sendFlower(B);

6.2 保護(hù)代理和虛擬代理

比如送花的人中年齡太大或者沒有寶馬懦趋,這種請求就可以直接在代理B處被拒絕掉,這種代理叫保護(hù)代理。

白臉A繼續(xù)保持良好的女神形象,不希望直接拒絕任何人,于是找了黑臉B來控制對A的訪問

代理B會在A心情好時再執(zhí)行new Flower,這叫虛擬代理,它會把一些開銷很大的對象,延遲到真正需要它的時候才去創(chuàng)建

var B = {
    receiveFlower:function(){
        A.listenGoodMood(function(){
            var flower = new flower();
            A.receiveFlower(flower);
        });
    }
}

在Javascript中并不容易實現(xiàn)保護(hù)代理枫振,因為我們無法判斷誰訪問了某個對象。而虛擬代理是最常用的一種代理模式萤彩,本章主要討論的也是虛擬代理粪滤。

6.3 虛擬代理實現(xiàn)圖片預(yù)加載

var myImage = (function(){
    // body...
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);

    return {
        setSrc : function(src){
            imgNode.src = src;
        }
    }
})();

var proxyImage = (function(){
    var img = new Image;
    img.load = function(){
        myImage.setSrc(this.src);
    }
    return {
        setSrc:function(src){
            myImage.setSrc('file://jdjisj.gif');
            img.src = src;
        }
    }

})()

myImage.setSrc('http:wwjjfjds.jpg');

6.4 代理的意義

不用代理的預(yù)加載圖片函數(shù)實現(xiàn)

var myImage = (function(){
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);
    var img = new Image;

    img.onload = function(){
        imgNode.src = img.src;
    };

    return {
        setSrc:function(){
            imgNode.src = 'file://dsd.gif';
            img.src = src;
        }
    }
})()

MyImage.setSrc('http://dsadsd.jpg');

面向?qū)ο笤O(shè)計的原則--單一職責(zé)原則

面向?qū)ο笤O(shè)計鼓勵將行為分布到細(xì)粒度的對象之中,如果一個對象承擔(dān)的職責(zé)過多雀扶,等于把這些職責(zé)耦合到了一起杖小,這中耦合會導(dǎo)致脆弱和低內(nèi)聚的設(shè)計。當(dāng)發(fā)生變化時愚墓,設(shè)計可能會遭到意外的破環(huán)予权。

面向?qū)ο蟪绦蛑校蠖鄶?shù)情況下浪册,若違反其他任何原則扫腺,同時將違反開放-封閉原則。這時刪預(yù)加載代碼就不得不動MyImage對象了

代理負(fù)責(zé)預(yù)加載圖片完成后把請求重新交給本體村象。

不需要預(yù)加載了只需要改成請求本體而不是請求代理對象即可

6.5 代理和本體接口的一致性

代理對象和本體都對外提供了setSrc方法笆环,在客戶看來攒至,代理對象和本體是一致的,代理接手請求的過程對于用戶來說是透明的躁劣,用戶并不清楚代理和本體的區(qū)別嗓袱。

  • 用戶可以放心的請求代理,他只關(guān)心是否能得到想要的結(jié)果

  • 在任何使用本體的地方都可以替換成使用代理

在Javascript這種語言中习绢,我們有時通過鴨子類型來檢測代理和本體是否都實現(xiàn)了setSrc方法,另外大多數(shù)時候甚至不做檢測蝙昙,全部依賴程序員的自覺性

沒有接口的世界

如果代理對象和本體對象都為一個函數(shù)(函數(shù)也是對象)闪萄,函數(shù)必然都能被執(zhí)行,則可以認(rèn)為它們也具有一致的“接口”

var myImage = (function(){
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);

    return function(src){
        imgNode.src = src;
    }
})();

var proxyImage = (function(){
    var img = new Image;
    img.onload = function(){
        myImage(this.src);
    }

    return function(src){
        myImage('file:fsfdf.gif');
        img.src = src;
    }
})();

proxyImage('http://sds.jpg');

6.6 虛擬代理合并HTTP請求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<input type="checkbox" name="" id="1">1
<input type="checkbox" name="" id="2">2
<input type="checkbox" name="" id="3">3
<input type="checkbox" name="" id="4">4
<input type="checkbox" name="" id="5">5
<input type="checkbox" name="" id="6">6
<input type="checkbox" name="" id="7">7
<input type="checkbox" name="" id="8">8
<input type="checkbox" name="" id="9">9

<script>
    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);
            }
        }
    }
</script>
</body>
</html>

如此頻繁的網(wǎng)絡(luò)請求將會帶來相當(dāng)大的開銷

var synchronousFile = function(id){
    console.log('開始同步文件奇颠,id為:' + id);
}

var proxySynchronousFile = (function(){
    var cache = [],timer;
    return function(id){
        cache.push(id);
        if(timer){
            return;
        }
        timer = setTimeout(function(){
            synchronousFile(cache.join(','));
            clearTimeout(timer);
            timer = null;
            cache.length = 0;
        },2000)
    }
})();

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

6.7 虛擬代理在惰性加載中的應(yīng)用

var miniConsole = (function(){
    var cache = [];
    var handler = function(ev){
        if(ev.keyCode === 113){
            var script = document.createElement('script');
            script.onload = function(){
                for(var i = 0, fn;fn = cache[i++];){
                    fn();
                }
            }
            script.src = 'miniConsole.js';
            document.getElementsByTagName('head')[0].appendChild(script);
            document.body.removeEventListener('keydown',handler);//只加載一次miniConsole.js
        }
    };
    document.body.addEventListener('keydown',handler,false);
    return {
        log:function(){
            var args = arguments;
            cache.push(function(){
                return miniConsole.log.apply(miniConsole,args);
            });
        }
    }
})();

miniConsole.log(11);

//miniConsole.js代碼
miniConsole = {
    log:function(){
        //真正代碼略
        console.log(Array.prototype.join.call(arguments));
    }
}

6.8 緩存代理

6.8.1 緩存代理的例子--計算乘積

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);//6
mult(2,3,4);//24

//加入緩存代理函數(shù)
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);
    }
})();

var a = proxyMult(1,2,3,4); //24
var b = proxyMult(1,2,3,4); //24
console.log(a,b)
開始計算
24 24

6.8.2 緩存代理用于ajax異步請求數(shù)據(jù)

已經(jīng)拉取的數(shù)據(jù)在某個地方被緩存之后败去,下次再請求同一頁的時候,便可以直接使用之前的數(shù)據(jù)烈拒。

這里也可以引入緩存代理圆裕,實現(xiàn)方式跟計算乘積的例子差不多,唯一不同的是荆几,請求是個異步操作吓妆,我們無法把 計算結(jié)果放在代理對象的緩存中,而是通過回調(diào)的方式

6.9 用高階函數(shù)動態(tài)創(chuàng)建代理

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);
var proxyPlus = createProxyFactory(plus);

console.log(proxyMult(1,2,3,4));
console.log(proxyMult(1,2,3,4));
console.log(proxyPlus(1,2,3,4));
console.log(proxyPlus(1,2,3,4));

6.10 其他代理模式

防火墻模式:控制網(wǎng)絡(luò)資源的訪問吨铸,保護(hù)主題不讓“壞人”接近
遠(yuǎn)程代理:為一個對象在不同的地址空間提供局部代表行拢,在JAVA中,遠(yuǎn)程代理可以是另一個虛擬機(jī)中的對象
保護(hù)代理:用于對象應(yīng)該有不同訪問權(quán)限的情況诞吱。
智能引用的次數(shù):取代了簡單的指針舟奠,它訪問對象時執(zhí)行一些附加操作,比如計算對象被引用的次數(shù)房维。
寫時復(fù)制代理:通常用于復(fù)制一個龐大對象的情況沼瘫。寫時復(fù)制代理延遲了復(fù)制的過程,當(dāng)對象被真正修改時咙俩,才對它進(jìn)行復(fù)制操作耿戚。寫時復(fù)制代理是虛擬代理的一種變體,DLL(操作系統(tǒng)中的動態(tài)鏈接庫)是其典型運用場景

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暴浦,一起剝皮案震驚了整個濱河市溅话,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歌焦,老刑警劉巖飞几,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異独撇,居然都是意外死亡屑墨,警方通過查閱死者的電腦和手機(jī)躁锁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卵史,“玉大人战转,你說我怎么就攤上這事∫郧” “怎么了槐秧?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長忧设。 經(jīng)常有香客問我刁标,道長,這世上最難降的妖魔是什么址晕? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任膀懈,我火速辦了婚禮,結(jié)果婚禮上谨垃,老公的妹妹穿的比我還像新娘启搂。我一直安慰自己,他們只是感情好刘陶,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布胳赌。 她就那樣靜靜地躺著,像睡著了一般匙隔。 火紅的嫁衣襯著肌膚如雪匈织。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天牡直,我揣著相機(jī)與錄音缀匕,去河邊找鬼。 笑死碰逸,一個胖子當(dāng)著我的面吹牛乡小,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饵史,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼满钟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了胳喷?” 一聲冷哼從身側(cè)響起湃番,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吭露,沒想到半個月后吠撮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡讲竿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年泥兰,在試婚紗的時候發(fā)現(xiàn)自己被綠了弄屡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡鞋诗,死狀恐怖膀捷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情削彬,我是刑警寧澤全庸,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站融痛,受9級特大地震影響糕篇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酌心,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挑豌。 院中可真熱鬧安券,春花似錦、人聲如沸氓英。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铝阐。三九已至址貌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間徘键,已是汗流浹背练对。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留吹害,地道東北人螟凭。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像它呀,于是被迫代替她去往敵國和親螺男。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品纵穿,去做同樣的事情下隧,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,729評論 2 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谓媒,服務(wù)發(fā)現(xiàn)淆院,斷路器,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,851評論 25 707
  • 大型經(jīng)典3D二戰(zhàn)坦克塔防手游強(qiáng)勢來襲句惯。動態(tài)光影的逼真畫面迫筑,個性化的獨特玩法宪赶,注重戰(zhàn)術(shù)的操作體驗,爆屏打擊的暢快感受...
    SGZKJYXGS閱讀 598評論 0 0
  • 因為布局文件的命名中出現(xiàn)兩個下劃線導(dǎo)致的脯燃。比如@id/+id a__b_c
    聶順閱讀 391評論 0 0