javascript設(shè)計模式(代理模式)[轉(zhuǎn)]

代理模式

代理是一個對象,它可以用來控制對本體對象的訪問,它與本體對象實現(xiàn)了同樣的接口,代理對象會把所有的調(diào)用方法傳遞給本體對象的;代理模式最基本的形式是對訪問進行控制,而本體對象則負(fù)責(zé)執(zhí)行所分派的那個對象的函數(shù)或者類,簡單的來講本地對象注重的去執(zhí)行頁面上的代碼,代理則控制本地對象何時被實例化,何時被使用;我們在上面的單體模式中使用過一些代理模式,就是使用代理模式實現(xiàn)單體模式的實例化,其他的事情就交給本體對象去處理;
代理的優(yōu)點:
代理對象可以代替本體被實例化,并使其可以被遠(yuǎn)程訪問;
它還可以把本體實例化推遲到真正需要的時候;對于實例化比較費時的本體對象,或者因為尺寸比較大以至于不用時不適于保存在內(nèi)存中的本體,我們可以推遲實例化該對象;

1、我們先來理解代理對象代替本體對象被實例化的列子;

比如現(xiàn)在京東ceo想送給奶茶妹一個禮物,但是呢假如該ceo不好意思送,或者由于工作忙沒有時間送,那么這個時候他就想委托他的經(jīng)紀(jì)人去做這件事,于是我們可以使用代理模式來編寫如下代碼:

// 先申明一個奶茶妹對象
var TeaAndMilkGirl = function(name) {
    this.name = name;
};
// 這是京東ceo先生
var Ceo = function(girl) {
    this.girl = girl;
    // 送結(jié)婚禮物 給奶茶妹
    this.sendMarriageRing = function(ring) {
        console.log("Hi " + this.girl.name + ", ceo送你一個禮物:" + ring);
    }
};
// 京東ceo的經(jīng)紀(jì)人是代理,來代替送
var ProxyObj = function(girl){
    this.girl = girl;
    // 經(jīng)紀(jì)人代理送禮物給奶茶妹
    this.sendGift = function(gift) {
        // 代理模式負(fù)責(zé)本體對象實例化
        (new Ceo(this.girl)).sendMarriageRing(gift);
    }
};
// 初始化
var proxy = new ProxyObj(new TeaAndMilkGirl("奶茶妹"));
proxy.sendGift("結(jié)婚戒"); // Hi 奶茶妹, ceo送你一個禮物:結(jié)婚戒

代碼如上的基本結(jié)構(gòu),TeaAndMilkGirl是一個被送的對象(這里是奶茶妹);Ceo是送禮物的對象,他保存了奶茶妹這個屬性,及有一個自己的特權(quán)方法sendMarriageRing就是送禮物給奶茶妹這么一個方法;然后呢他是想通過他的經(jīng)紀(jì)人去把這件事完成,于是需要創(chuàng)建一個經(jīng)濟人的代理模式,名字叫ProxyObj;他的主要做的事情是,把ceo交給他的禮物送給ceo的情人,因此該對象同樣需要保存ceo情人的對象作為自己的屬性,同時也需要一個特權(quán)方法sendGift,該方法是送禮物,因此在該方法內(nèi)可以實例化本體對象,這里的本體對象是ceo送花這件事情,因此需要實例化該本體對象后及調(diào)用本體對象的方法(sendMarriageRing).
最后我們初始化是需要代理對象ProxyObj;調(diào)用ProxyObj對象的送花這個方法(sendGift)即可;
對于我們提到的優(yōu)點,第二點的話,我們下面可以來理解下虛擬代理,虛擬代理用于控制對那種創(chuàng)建開銷很大的本體訪問,它會把本體的實例化推遲到有方法被調(diào)用的時候;比如說現(xiàn)在有一個對象的實例化很慢的話,不能在網(wǎng)頁加載的時候立即完成,我們可以為其創(chuàng)建一個虛擬代理,讓他把該對象的實例推遲到需要的時候。
2、理解使用虛擬代理實現(xiàn)圖片的預(yù)加載
在網(wǎng)頁開發(fā)中,圖片的預(yù)加載是一種比較常用的技術(shù),如果直接給img標(biāo)簽節(jié)點設(shè)置src屬性的話,如果圖片比較大的話,或者網(wǎng)速相對比較慢的話,那么在圖片未加載完之前,圖片會有一段時間是空白的場景,這樣對于用戶體驗來講并不好,那么這個時候我們可以在圖片未加載完之前我們可以使用一個loading加載圖片來作為一個占位符,來提示用戶該圖片正在加載,等圖片加載完后我們可以對該圖片直接進行賦值即可;下面我們先不用代理模式來實現(xiàn)圖片的預(yù)加載的情況下代碼如下:
第一種方案:不使用代理的預(yù)加載圖片函數(shù)如下

// 不使用代理的預(yù)加載圖片函數(shù)如下
            var myImage = (function() {
                var imgNode = document.createElement("img");
                document.body.appendChild(imgNode);
                var img = new Image();
                img.onload = function() {
                    imgNode.src = this.src;
                };
                return {
                    setSrc: function(src) {
                        imgNode.src = "img/g.jpg"
                        img.src = src;
                    }
                }
            })();
            // 調(diào)用方式
            myImage.setSrc("http://img1.imgtn.bdimg.com/i=yxt.jpg");

如上代碼是不使用代理模式來實現(xiàn)的代碼;
第二種方案:使用代理模式來編寫預(yù)加載圖片的代碼如下:

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("img/g.jpg");
                        img.src = src;
                    }
                }
            })();
            // 調(diào)用方式
            ProxyImage.setSrc("http://img1.imgtn.bdimg.com/i=yxt.jpg");

第一種方案是使用一般的編碼方式實現(xiàn)圖片的預(yù)加載技術(shù),首先創(chuàng)建imgNode元素,然后調(diào)用myImage.setSrc該方法的時候,先給圖片一個預(yù)加載圖片,當(dāng)圖片加載完的時候,再給img元素賦值,第二種方案是使用代理模式來實現(xiàn)的,myImage函數(shù)只負(fù)責(zé)創(chuàng)建img元素,代理函數(shù)ProxyImage負(fù)責(zé)給圖片設(shè)置loading圖片,當(dāng)圖片真正加載完后的話,調(diào)用myImage中的myImage.setSrc方法設(shè)置圖片的路徑;
他們之間的 優(yōu)缺點如下:

第一種方案一般的方法代碼的耦合性太高,一個函數(shù)內(nèi)負(fù)責(zé)做了幾件事情,比如創(chuàng)建img元素,和實現(xiàn)給未加載圖片完成之前設(shè)置loading加載狀態(tài)等多項事情,未滿足面向?qū)ο笤O(shè)計原則中單一職責(zé)原則;并且當(dāng)某個時候不需要代理的時候,需要從myImage函數(shù)內(nèi)把代碼刪掉,這樣代碼耦合性太高。

第二種方案使用代理模式,其中myImage函數(shù)只負(fù)責(zé)做一件事,創(chuàng)建img元素加入到頁面中,其中的加載loading圖片交給代理函數(shù)ProxyImage去做,當(dāng)圖片加載成功后,代理函數(shù)ProxyImage會通知及執(zhí)行myImage函數(shù)的方法,同時當(dāng)以后不需要代理對象的話,我們直接可以調(diào)用本體對象的方法即可;

從上面代理模式我們可以看到,代理模式和本體對象中有相同的方法setSrc,這樣設(shè)置的話有如下2個優(yōu)點:
用戶可以放心地請求代理,他們只關(guān)心是否能得到想要的結(jié)果。假如我門不需要代理對象的話,直接可以換成本體對象調(diào)用該方法即可。

在任何使用本體對象的地方都可以替換成使用代理。
設(shè)計模式:http://www.cnblogs.com/tugenhua0707/p/5198407.html

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

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

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