javascript 代理模式

所謂的的代理模式就是為一個對象找一個替代對象,以便對原對象進(jìn)行訪問酗洒。

使用代理的原因是我們不愿意或者不想對原對象進(jìn)行直接操作,我們使用代理就是讓它幫原對象進(jìn)行一系列的操作,等這些東西做完后告訴原對象就行了酿矢。就像我們生活的那些明星的助理經(jīng)紀(jì)人一樣。

我們舉一個明星買鞋子的例子怎燥。

1.明星自己去買鞋瘫筐。

// 定義一個鞋子類
var Shoes = function(name){
    this.name = name;
};

Shoes.prototype.getName = function() {
    return this.name;
};

// 定義一個明星對象
var star = {
    buyShoes: function(shoes) {
        console.log('買到了一雙' + shoes.getName());
    }
}

star.buyShoes(new Shoes('皮鞋')); // "買到了一雙皮鞋"

當(dāng)然了,想買鞋這種事铐姚,一般都會交給助理去做策肝。

2.明星讓助理代自己去買鞋。

// 定義一個鞋子類
var Shoes = function(name){
    this.name = name;
};

Shoes.prototype.getName = function() {
    return this.name;
};

// 定義一個助理對象
 
var assistant = {
    buyShoes: function(shoes) {
        star.buyShoes(shoes.getName())
    }
};

// 定義一個明星對象
var star = {
    buyShoes: function(name) {
        console.log('買到了一雙' + name);
    }

};

assistant.buyShoes(new Shoes('高跟鞋')); // "買到了一雙高跟鞋"

怎么樣隐绵,代理就是這么簡單之众,可能到這里有的同學(xué)會比較疑惑,代理的實現(xiàn)結(jié)果不是和不使用一樣嗎依许?是的棺禾,一樣的實現(xiàn)結(jié)果是必須的,但是峭跳,值用代理并不是我們看到的那樣將簡單的事情復(fù)雜化了膘婶,代理的使用場景當(dāng)然不是這種簡單的場景,而是針對一些比較復(fù)雜或特殊的情況使用蛀醉,這里只是為了舉例說明代理的實現(xiàn)悬襟。下面就介紹一些使用場景。

代理使用場景

繼續(xù)上面的明星買鞋子的問題拯刁。在生活中我們會遇到商店在營業(yè)時間脊岳,而你在工作時間,由于要掙錢同時又要花錢,所以逸绎,會找一個代理惹恃;就像春節(jié)快到了,你沒時間或者搶不到票棺牧,就會找票販子一樣巫糙;像現(xiàn)在的代購,則是你不能出國颊乘,或者對國外不了解参淹,就找能出國,對國外了解的人幫你買東西一樣乏悄。我們知道每家商店都有自己的營業(yè)時間和休息時間浙值,這里我們用(8:00~20:00)算作營業(yè)時間。

// 定義一個鞋子類
var Shoes = function(name){
    this.name = name;
};

Shoes.prototype.getName = function() {
    return this.name;
};
// 添加了一個business方法檩小,通過當(dāng)前的時間來判斷是否能買到鞋子开呐。
Shoes.prototype.business = function() {
    var curTime = new Date().getHours();
    return  curTime >= 8 && curTime <= 20 ? that.getName() : '"非營業(yè)時間!"';
    
}

// 定義一個助理對象
var assistant = {
    buyShoes: function(shoes) {
        star.buyShoes(shoes.getName())
    }
};

// 定義一個明星對象
var star = {
    buyShoes: function(name) {
        console.log('買到了一雙' + name);
    }
};

assistant.buyShoes(new Shoes('高跟鞋')); // "買到了一雙高跟鞋"

保護(hù)代理

助理作為明星的代理规求,不僅可以幫助明星買東西筐付,同時還有幫助明星過濾的東西的職責(zé),比如說阻肿,有粉絲要送明星花(不是什么樣的花都收的)瓦戚,有人要找明星代言廣告(不是什么樣的廣告都代言的)。

// 定義一個廣告類
var Ad = function(price){
    this.price = price;
};

Ad.prototype.getPrice = function() {
    return this.price;
};

// 定義一個助理對象
var assistant = {
    init: function(ad) {
        var money = ad.getPrice();
        if(money > 300) {
            this.receiveAd(money);
        } else {
            this.rejectAd();
        }
    },
    receiveAd: function(price) {
        star.receiveAd(price);
    },
    rejectAd: function() {
        star.rejectAd();
    }
};

// 定義一個明星對象
var star = {
    receiveAd: function(price) {
        console.log('廣告費' + price + '萬元');
    },
    rejectAd: function() {
        console.log('拒絕小制作丛塌!');
    }
};

assistant.init(new Ad(5)); // "拒絕小制作较解!"
assistant.init(new Ad(500)); // "廣告費500萬元"

像這種明星向助理授權(quán),如:什么樣價位的廣告可以接赴邻,什么樣的鮮花可以接等等印衔。這樣將一些業(yè)務(wù)的處理交給助理或者經(jīng)紀(jì)人處理,而自己則位于幕后乍楚,無疑給自己減少了不必要的麻煩当编,這樣明星就處于一種保護(hù)狀態(tài)。在現(xiàn)實生活中的例子比比皆是徒溪,同樣在我們的程序語言開發(fā)中也是比較常見忿偷,尤其是網(wǎng)絡(luò)和進(jìn)程這方面,相信做過nodjs開發(fā)的同學(xué)或多或少會遇到臊泌。

虛擬代理

在開發(fā)中鲤桥,我們往往將 new Ad('5') 這個對象的實例化操作,放到函數(shù)內(nèi)部執(zhí)行渠概,這樣的操作會減少不必要的實例化對象的開銷茶凳,造成資源的浪費嫂拴。這種使用的情況我們將之成為虛擬代理。

下面就介紹一個常見的虛擬代理——圖片的預(yù)加載贮喧。

圖片預(yù)加載是一種常見的前端技術(shù)筒狠,由于圖片過大或者網(wǎng)絡(luò)不佳,我們不會直接給某個img標(biāo)簽節(jié)點設(shè)置src屬性箱沦,而是使用一張loading圖片作為占位符辩恼,然后用異步的方式來家在加載圖片,等到圖片加載完畢谓形,我們再把它填充到img的節(jié)點里灶伊。

var preImage = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);
    var img = new Image; 
    img.onload = function() {
        imgNode.src = img.src;
    }; 
 
    return {
        setSrc: function(src) {
            imgNode.src = '../loading.gif';
            img.src = src;
        }
    }
})(); 
 
preImage.setSrc('https://cn.bing.com/az/hprichbg/rb/TadamiTrain_ZH-CN13495442975_1920x1080.jpg'); 

到這里,圖片的預(yù)加載功能已經(jīng)實現(xiàn)寒跳,但是往往體現(xiàn)一段代碼的是否更優(yōu)秀聘萨,是看你的代碼是否易于維護(hù),特別是對于海量的代碼童太。第一點米辐,這段代碼不符合單一職責(zé),我們把負(fù)責(zé)圖片預(yù)加載的功能康愤,對img元素的處理放在了一個函數(shù)體內(nèi)儡循,尤其是沒有將代碼變化的部分和未變化的部分分開;第二點征冷,就是將來我們的網(wǎng)速非常好,我們不用再擔(dān)心由于網(wǎng)絡(luò)不佳而造成的顯示效果問題誓琼,那么關(guān)于圖片預(yù)加載的功能就要去掉检激。

我們可以嘗試使用代理來實現(xiàn),代碼如下:

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

var preImage = (function() {
    var img = new Image; 
    img.onload = function() {
        myImage.setSrc = img.src;
    }; 
 
    return {
        setSrc: function(src) {
            myImage.setSrc( '../loading.gif');
            img.src = src;
        }
    }
})(); 
 
preImage.setSrc('https://cn.bing.com/az/hprichbg/rb/TadamiTrain_ZH-CN13495442975_1920x1080.jpg'); 

這樣我們就將圖片預(yù)加載和為img元素節(jié)點設(shè)置src分開來腹侣。

代理和被代理對象的一致性

因為代理要實現(xiàn)和被代理對象實際處理一樣的效果叔收,所以,在實現(xiàn)代理對象時傲隶,原對象有的方法饺律,代理對象一樣有,這樣可以保證跺株,用戶在操作代理對象時就像在操作原對象一樣复濒。

緩存代理

緩存代理就是將代理加緩存,下面是一個求和的例子:

var multAdd = function() {
    var res = 0;
    for (var i = 0, l = arguments.length; i < l; i++) {
        res = res + arguments[i]
    }

    return res;
};

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

proxyAdd(1, 2, 3); // 6
proxyAdd(1, 2, 3); // 6

我們不用代理當(dāng)然也能實現(xiàn)緩存就和乒省,但是為了達(dá)到單一職責(zé)巧颈,我們可以讓multAdd實現(xiàn)求和,而緩存則放在代理中來實現(xiàn)袖扛。

當(dāng)然砸泛,還有其他的分類代理十籍,比如,智能代理唇礁,遠(yuǎn)程代理勾栗。但是在JavaScript中我們使用最多,也最常見的就是虛擬代理和緩存代理盏筐。

設(shè)計模式周周講

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末械姻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子机断,更是在濱河造成了極大的恐慌楷拳,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吏奸,死亡現(xiàn)場離奇詭異欢揖,居然都是意外死亡,警方通過查閱死者的電腦和手機奋蔚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門她混,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泊碑,你說我怎么就攤上這事坤按。” “怎么了馒过?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵臭脓,是天一觀的道長。 經(jīng)常有香客問我腹忽,道長来累,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任窘奏,我火速辦了婚禮嘹锁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘着裹。我一直安慰自己领猾,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布骇扇。 她就那樣靜靜地躺著摔竿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匠题。 梳的紋絲不亂的頭發(fā)上拯坟,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音韭山,去河邊找鬼郁季。 笑死冷溃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梦裂。 我是一名探鬼主播似枕,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼年柠!你這毒婦竟也來了凿歼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤冗恨,失蹤者是張志新(化名)和其女友劉穎答憔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掀抹,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡虐拓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了傲武。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓉驹。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖揪利,靈堂內(nèi)的尸體忽然破棺而出态兴,到底是詐尸還是另有隱情,我是刑警寧澤疟位,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布瞻润,位于F島的核電站,受9級特大地震影響献汗,放射性物質(zhì)發(fā)生泄漏敢订。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一罢吃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昭齐,春花似錦尿招、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至里覆,卻和暖如春丧荐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喧枷。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工虹统, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弓坞,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓车荔,卻偏偏與公主長得像渡冻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子忧便,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,178評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理族吻,服務(wù)發(fā)現(xiàn),斷路器珠增,智...
    卡卡羅2017閱讀 134,664評論 18 139
  • 遇見你是前世的起因超歌,離開你是命中的注定。也許你我的緣份蒂教,多了他也就變了巍举,坦誠多了,也就透明了悴品,彼此沒有了神秘禀综,少了...
    伊凡軒閱讀 169評論 0 0
  • 兩個人在一起,有甜蜜苔严,有心酸定枷,但一切都會過去。因為彼此相愛著届氢。 曾經(jīng)以為愛會讓她幸福的過一輩子欠窒,不管能不能在一起,...
    哈士奇2016閱讀 313評論 0 0
  • 哪些我們應(yīng)該教給孩子?哪些又不能教給孩子寂祥?全是具體的方法荐虐,非常難得。 九十件必須教給孩子的事 下面的90件事情是上...
    夢中幽蘭閱讀 328評論 0 0