摘要:虛擬代理在開發中,我們往往將這個對象的實例化操作,放到函數內部執行,這樣的操作會減少不必要的實例化對象的開銷,造成資源的浪費。這種使用的情況我們將之成為虛擬代理。但是在中我們使用最多,也最常見的就是虛擬代理和緩存代理。
所謂的的代理模式就是為一個對象找一個替代對象,以便對原對象進行訪問。
使用代理的原因是我們不愿意或者不想對原對象進行直接操作,我們使用代理就是讓它幫原對象進行一系列的操作,等這些東西做完后告訴原對象就行了。就像我們生活的那些明星的助理經紀人一樣。
我們舉一個明星買鞋子的例子。
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("皮鞋")); // "買到了一雙皮鞋"
當然了,想買鞋這種事,一般都會交給助理去做。
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("高跟鞋")); // "買到了一雙高跟鞋"
怎么樣,代理就是這么簡單,可能到這里有的同學會比較疑惑,代理的實現結果不是和不使用一樣嗎?是的,一樣的實現結果是必須的,但是,值用代理并不是我們看到的那樣將簡單的事情復雜化了,代理的使用場景當然不是這種簡單的場景,而是針對一些比較復雜或特殊的情況使用,這里只是為了舉例說明代理的實現。下面就介紹一些使用場景。
代理使用場景繼續上面的明星買鞋子的問題。在生活中我們會遇到商店在營業時間,而你在工作時間,由于要掙錢同時又要花錢,所以,會找一個代理;就像春節快到了,你沒時間或者搶不到票,就會找票販子一樣;像現在的代購,則是你不能出國,或者對國外不了解,就找能出國,對國外了解的人幫你買東西一樣。我們知道每家商店都有自己的營業時間和休息時間,這里我們用(8:00~20:00)算作營業時間。
// 定義一個鞋子類 var Shoes = function(name){ this.name = name; }; Shoes.prototype.getName = function() { return this.name; }; // 添加了一個business方法,通過當前的時間來判斷是否能買到鞋子。 Shoes.prototype.business = function() { var curTime = new Date().getHours(); return curTime >= 8 && curTime <= 20 ? that.getName() : ""非營業時間!""; } // 定義一個助理對象 var assistant = { buyShoes: function(shoes) { star.buyShoes(shoes.getName()) } }; // 定義一個明星對象 var star = { buyShoes: function(name) { console.log("買到了一雙" + name); } }; assistant.buyShoes(new Shoes("高跟鞋")); // "買到了一雙高跟鞋"保護代理
助理作為明星的代理,不僅可以幫助明星買東西,同時還有幫助明星過濾的東西的職責,比如說,有粉絲要送明星花(不是什么樣的花都收的),有人要找明星代言廣告(不是什么樣的廣告都代言的)。
// 定義一個廣告類 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萬元"
像這種明星向助理授權,如:什么樣價位的廣告可以接,什么樣的鮮花可以接等等。這樣將一些業務的處理交給助理或者經紀人處理,而自己則位于幕后,無疑給自己減少了不必要的麻煩,這樣明星就處于一種保護狀態。在現實生活中的例子比比皆是,同樣在我們的程序語言開發中也是比較常見,尤其是網絡和進程這方面,相信做過nodjs開發的同學或多或少會遇到。
虛擬代理在開發中,我們往往將 new Ad("5") 這個對象的實例化操作,放到函數內部執行,這樣的操作會減少不必要的實例化對象的開銷,造成資源的浪費。這種使用的情況我們將之成為虛擬代理。
下面就介紹一個常見的虛擬代理——圖片的預加載。
圖片預加載是一種常見的前端技術,由于圖片過大或者網絡不佳,我們不會直接給某個img標簽節點設置src屬性,而是使用一張loading圖片作為占位符,然后用異步的方式來家在加載圖片,等到圖片加載完畢,我們再把它填充到img的節點里。
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");
到這里,圖片的預加載功能已經實現,但是往往體現一段代碼的是否更優秀,是看你的代碼是否易于維護,特別是對于海量的代碼。第一點,這段代碼不符合單一職責,我們把負責圖片預加載的功能,對img元素的處理放在了一個函數體內,尤其是沒有將代碼變化的部分和未變化的部分分開;第二點,就是將來我們的網速非常好,我們不用再擔心由于網絡不佳而造成的顯示效果問題,那么關于圖片預加載的功能就要去掉。
我們可以嘗試使用代理來實現,代碼如下:
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");
這樣我們就將圖片預加載和為img元素節點設置src分開來。
代理和被代理對象的一致性因為代理要實現和被代理對象實際處理一樣的效果,所以,在實現代理對象時,原對象有的方法,代理對象一樣有,這樣可以保證,用戶在操作代理對象時就像在操作原對象一樣。
緩存代理緩存代理就是將代理加緩存,下面是一個求和的例子:
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
我們不用代理當然也能實現緩存就和,但是為了達到單一職責,我們可以讓multAdd實現求和,而緩存則放在代理中來實現。
當然,還有其他的分類代理,比如,智能代理,遠程代理。但是在JavaScript中我們使用最多,也最常見的就是虛擬代理和緩存代理。
設計模式周周講
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92641.html
摘要:面向對象設計里的設計模式之代理模式,相信很多朋友已經很熟悉了。代表當前執行方法的實例,即方法調用者。代表具體的方法名稱。現在我們再次調用,傳入構造器返回的代理對象打印輸出,代理邏輯生效了和的一樣優雅地實現了代理設計模式。 showImg(https://segmentfault.com/img/remote/1460000016760603);面向對象設計里的設計模式之Proxy(代理...
摘要:注意事項聲明函數時候處理業務邏輯區分和單例的區別,配合單例實現初始化構造函數大寫字母開頭推薦注意的成本。簡單工廠模式使用一個類通常為單體來生成實例。 @(書籍閱讀)[JavaScript, 設計模式] 常見設計模式 一直對設計模式不太懂,花了一下午加一晚上的時間,好好的看了看各種設計模式,并總結了一下。 設計模式簡介 設計模式概念解讀 設計模式的發展與在JavaScript中的應用 ...
摘要:保護代理和虛擬代理保護代理當有許多需求要向某對象發出一些請求時,可以設置保護代理,通過一些條件判斷對請求進行過濾。虛擬代理在程序中可以能有一些代價昂貴的操作。而虛擬代理是最常用的一種代理模式。 代理模式 代理模式是為一個對象提供一個代用品或占位符,以便控制對它的訪問。 保護代理和虛擬代理 保護代理:當有許多需求要向某對象發出一些請求時,可以設置保護代理,通過一些條件判斷對請求進行過濾。...
摘要:缺點不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。預防低水平人員帶來的風險。開閉原則,高拓展性。這里的訂閱者稱為觀察者,而被觀察者稱為發布者,當一個事件發生,發布者會發布通知所有訂閱者,并常常以事件對象形式傳遞消息。 介紹 最近開始給自己每周訂個學習任務,學習結果反饋為一篇文章的輸出,做好學習記錄。 這一周(02.25-03.03)我定的目標是《JavaScript 模式》...
摘要:著名的代理模式例子為引用計數英語指針對象。是一個構造函數,是被代理的對象,是聲明了各類代理操作的對象,最終返回一個代理對象。在給一個目標對象為構造函數的代理對象構造實例時觸發該操作,比如在執行時。 所謂的代理者是指一個類別可以作為其它東西的接口。代理者可以作任何東西的接口:網絡連接、內存中的大對象、文件或其它昂貴或無法復制的資源。 著名的代理模式例子為引用計數(英語:reference...
摘要:虛擬代理延遲執行虛擬代理的目的,是將開銷大的運算延遲到需要時再執行。 showImg(https://segmentfault.com/img/bVbuitm?w=800&h=600); 代理模式:為一個對象提供一個代用品或占位符,以便控制它的訪問。 當我們不方便直接訪問某個對象時,或不滿足需求時,可考慮使用一個替身對象來控制該對象的訪問。替身對象可對請求預先進行處理,再決定是否轉交給...
閱讀 6866·2021-09-22 15:36
閱讀 5687·2021-09-02 10:20
閱讀 1869·2019-08-30 15:44
閱讀 2653·2019-08-29 14:06
閱讀 1153·2019-08-29 11:17
閱讀 1585·2019-08-26 14:05
閱讀 3093·2019-08-26 13:50
閱讀 1551·2019-08-26 10:26