javascript設(shè)計(jì)模式( 三)代理模式

代理模式,顧名思義,就是A要對(duì)C做一件事情,讓B幫忙做(怎么聽起來(lái)怪怪的)。

// A
var A = function(){
    this.talk = function(){
        console.log("能帶我打dota2嗎");
    }
};
//C
var C= function(){
    this.B = new B();
    this.talk = function(){
        console.log("一個(gè)人打dota2好沒(méi)意思啊");
        this.B.talk();
    }
}
//我
var B = function(){
    this.A = new A();
    this.talk = function(){
        console.log("A 讓我問(wèn)你");
        this.A.talk();
    }
}
//執(zhí)行
new C().talk();
//結(jié)果
/**
 * 一個(gè)人打dota2好沒(méi)意思啊
 * A 讓我問(wèn)你
 * 能帶我打dota2嗎
 */

下面寫幾個(gè)常見(jiàn)的使用代理模式的例子

在網(wǎng)頁(yè)開發(fā)中,圖片的預(yù)加載是一種比較常用的技術(shù),如果直接給img標(biāo)簽節(jié)點(diǎn)設(shè)置src屬性的話,如果圖片比較大的話,或者網(wǎng)速相對(duì)比較慢的話,那么在圖片未加載完之前,圖片會(huì)有一段時(shí)間是空白的場(chǎng)景,這樣對(duì)于用戶體驗(yàn)來(lái)講并不好,那么這個(gè)時(shí)候我們可以在圖片未加載完之前我們可以使用一個(gè)loading加載圖片。

//使用代理模式的寫法
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("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif");
            img.src = src;
        }
    }
})();

// 調(diào)用方式
ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");

如上代碼所示,其中myImage 函數(shù)只負(fù)責(zé)做一件事,創(chuàng)建img元素加入到頁(yè)面中,其中的加載loading圖片交給代理函數(shù)ProxyImage 去做,當(dāng)圖片加載成功后,代理函數(shù)ProxyImage 會(huì)通知及執(zhí)行myImage 函數(shù)的方法,同時(shí)當(dāng)以后不需要代理對(duì)象的話,我們直接可以調(diào)用本體對(duì)象的方法即可。
代理模式還可以用在需要多次提交數(shù)據(jù)的地方,比如,有表格數(shù)據(jù),每一條數(shù)據(jù)前面有復(fù)選框按鈕,當(dāng)點(diǎn)擊復(fù)選框按鈕時(shí)候,需要獲取該id后需要傳遞給給服務(wù)器發(fā)送ajax請(qǐng)求,服務(wù)器端需要記錄這條數(shù)據(jù),去請(qǐng)求,如果我們每當(dāng)點(diǎn)擊一下向服務(wù)器發(fā)送一個(gè)http請(qǐng)求的話,對(duì)于服務(wù)器來(lái)說(shuō)壓力比較大,網(wǎng)絡(luò)請(qǐng)求比較頻繁,但是如果現(xiàn)在該系統(tǒng)的實(shí)時(shí)數(shù)據(jù)不是很高的話,我們可以通過(guò)一個(gè)代理函數(shù)收集一段時(shí)間內(nèi)(比如說(shuō)2-3秒)的所有id,一次性發(fā)ajax請(qǐng)求給服務(wù)器,相對(duì)來(lái)說(shuō)網(wǎng)絡(luò)請(qǐng)求降低了, 服務(wù)器壓力減少了;

// 本體函數(shù)
var mainFunc = function(ids) {
    console.log(ids); // 即可打印被選中的所有的id
    // 再把所有的id一次性發(fā)ajax請(qǐng)求給服務(wù)器端
};
// 代理函數(shù) 通過(guò)代理函數(shù)獲取所有的id 傳給本體函數(shù)去執(zhí)行
var proxyFunc = (function(){
    var cache = [],  // 保存一段時(shí)間內(nèi)的id
        timer = null; // 定時(shí)器
    return function(checkboxs) {
        // 判斷如果定時(shí)器有的話,不進(jìn)行覆蓋操作
        if(timer) {
            return;
        }
        timer = setTimeout(function(){
            // 在2秒內(nèi)獲取所有被選中的id,通過(guò)屬性isflag判斷是否被選中
            for(var i = 0,ilen = checkboxs.length; i < ilen; i++) {
                if(checkboxs[i].hasAttribute("isflag")) {
                    var id = checkboxs[i].getAttribute("data-id");
                    cache[cache.length] = id;
                }
            }
            mainFunc(cache.join(',')); // 2秒后需要給本體函數(shù)傳遞所有的id
            // 清空定時(shí)器
            clearTimeout(timer);
            timer = null;
            cache = [];
        },2000);
    }
})();
var checkboxs = document.getElementsByClassName("j-input");
for(var i = 0,ilen = checkboxs.length; i < ilen; i+=1) {
    (function(i){
        checkboxs[i].onclick = function(){
            if(this.checked) {
                // 給當(dāng)前增加一個(gè)屬性
                this.setAttribute("isflag",1);
            }else {
                this.removeAttribute('isflag');
            }
            // 調(diào)用代理函數(shù)
            proxyFunc(checkboxs);
        }

    })(i);
}

緩存代理可以為一些開銷大的運(yùn)算結(jié)果提供暫時(shí)的存儲(chǔ),在下次運(yùn)算時(shí),如果傳遞進(jìn)來(lái)的參數(shù)跟之前一致,則可以返回前面的運(yùn)算結(jié)果。

// 計(jì)算乘積
var mult = function(){
    var a = 1;
    for( var i = 0, l = arguments.length; i < l; i++){
        a = a * arguments[i];
    }
    return a;
};
// 計(jì)算加和
var plus = function () {
  var a = 0;
    for( var i = 0, l = arguments.length; i < l; i++ ){
        a += arguments[i];
    }
    return a;
};
// 創(chuàng)建緩存代理的工廠
var createProxyFactory = function( fn ){
    var cache = {}; // 緩存 - 存放參數(shù)和計(jì)算后的值
    return function(){
        var args = Array.prototype.join.call(arguments, "-");
        if( args in cache ){ // 判斷出入的參數(shù)是否被計(jì)算過(guò)
            console.log( "使用緩存代理" );
            return cache[args];
        }
        return cache[args] = fn.apply( this, arguments );
    }
};
// 創(chuàng)建代理
var proxyMult = createProxyFactory( mult ),
    proxyPlus = createProxyFactory( plus );

console.log( proxyMult( 1, 2, 3, 4 ) ); // 輸出: 24
console.log( proxyMult( 1, 2, 3, 4 ) ); // 輸出: 緩存代理 24
console.log( proxyPlus( 1, 2, 3, 4 ) ); // 輸出: 10
console.log( proxyPlus( 1, 2, 3, 4 ) ); // 輸出: 緩存代理 10
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,116評(píng)論 2 17
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 代理是一個(gè)對(duì)象,它可以用來(lái)控制對(duì)本體對(duì)象的訪問(wèn),它與本體對(duì)象實(shí)現(xiàn)了同樣的接口,代理對(duì)象會(huì)把所有的調(diào)用方法傳遞給本體...
    JSUED閱讀 359評(píng)論 0 0
  • 怡情把酒徒傷月,才子柔腸奔放多。 墻里詞章起災(zāi)禍,烏臺(tái)一紙落東坡。 詩(shī)文書畫稱騷客,雅士黃州煮肉鍋。 滿腹經(jīng)綸遭落...
    青漄閱讀 600評(píng)論 63 13
  • 01成功的路上并不擁擠,因?yàn)槌晒κ菍儆谏贁?shù)人的。 俞敏洪上大學(xué)時(shí)候,為了提升英語(yǔ)水平,每天在北大的小樹林里背單詞,...
    瓜子向日葵閱讀 884評(píng)論 1 8

友情鏈接更多精彩內(nèi)容