上一篇<<JavaScript 設計模式之工廠模式>>javascript
代理模式是爲一個對象提供一個代用品或佔位符,以便控制對它的訪問 代理模式的用處(我的理解): 爲了保障當前對象的單一職責(相對獨立性), 而須要建立另外一個對象來處理調用當前對象以前的一些邏輯以提升代碼的效率、狀態判斷等。 代理模式中最經常使用的是虛擬代理和緩存代理
在現實生活中,能夠找到不少代理模式使用的場景。明星都有經紀人做爲代理。若是請明星來演出,就要先同他的經紀人溝通,談好相應的細節與報酬。再交給明星。
需求:公司(Company)經過經紀人(agent)找明星(start)開演唱會java
//演唱會 var Concert = function(){} //公司 var Company = { askforconcert: function(target){ var concert = new Concert(); target.openconcert(concert ) } } //明星 var star = { openconcert: function(concert){ console.log("明星贊成開一場演唱會") } } //經紀人代理 var agent = { openconcert: function(concert){ star.openconcert(concert) } } //執行 Company.askforconcert(agent); //=>明星贊成開一場演唱會 /*這樣 company直接把請求發給agent,agent再轉給star,這樣就完成了一個簡單的代理模式 (compan=>agent=>star)*/ //經濟人能夠幫助 明星過濾掉一些請求,好比 錢不夠多或者場地不夠好,這種請求能夠直接在經紀人出被過濾拒絕掉。 //這種代理就叫作保護代理。 //由經紀人Agent來控制對明星star的訪問。
- 若是A 經過 B 送花給C,咱們能夠在A的時候new 一個 flower傳遞給代理B,再由B決定何時或者是否要再轉交個最終的target C。new Flower這個操做能夠交給B,B決定能夠送花給C的時候再由B作 new Flower的操做。這種模式就叫作虛擬代理。虛擬代理把一些開銷很大的對象,延遲到真正須要它的時候纔去建立ajax
var Flower = function(){ this.price = 150 } var a = { sendflower: function(target){ var flower = new Flower() target.receiveFlower(flower ) } } var b = { receiveFlower: function(flower){ if(flower.price < 100){ console.log("太便宜了,女神表示一臉嫌棄") return false }else{ c.receiveFlower(flower) } }, } var c = { receiveFlower: function(){ console.log("接受了鮮花") } }
//不使用代理 var preLoadImage = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode) var img = new Image(); img.onload = function(){ imgNode.src = img.src } return { setSrc: function(src){ imgNode.src = "loading.gif"; img.src = src; } } })()
//使用代理模式的實現方式 var image = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode); return { setSrc: function(src){ imgNode.src = src; } } })() //代理 var proxyImage = (function(){ var img = new Image(); img.onload = function(){ // 圖片加載完成,正式加載圖片 image.setSrc = img.src; } return { setSrc: function(src){ image.setSrc = "loading.gif"; img.src = src; } } })
單一職責原則
單一職責指的是,對一個類而言,應該僅有一個引發他變化的緣由。若是一個對象承擔了多個原則,就意味着這個對象將變得巨大,引發他變化的緣由可能也會有多個。面向對象設計鼓勵將行爲分不到細粒度的對象之中,若是一個對象承擔的職責過多,等於把這些值得耦合到了一塊兒,這種耦合會致使脆弱和低內聚的設計。當變化發生時,設計可能會遭到意外的破壞。(書中93頁)後端
preLoadImage方法,承擔了添加img標籤,還有預加載兩個功能,代碼耦合到了一塊兒,當我修改添加標籤時,可能會影響到另外一部分功能。設計模式
而用代理方法重構後,image方法只負責建立標籤,設置src,預加載功能交給了proxyImage,解除了耦合的代碼,兩個功能互不干擾。數組
var syncFile = function(id){ $.ajax({ data: { id: id } })... } //綁定事件 for(var i = 0;i<fileObjArr.length;i++){ fileObjArr[i].onclick = function(){ if(this.checked === true){ syncFile(this.id) } } }
這裏有個很嚴重的問題,每點一個都會發送一個ajax請求,性能上,這是一個很大的開銷緩存
需求: 文件同步穿,選中的文件會被上傳到服務器上,解決方法,咱們能夠 經過一個代理函數,來收集一段時間內的請求,將請求的參數緩存起來,與後端人員協商將選中的id做爲一個數組傳到後臺保存。服務器
var syncFile = function(ids){ $.ajax({ data: { id: ids } })... } var proxyFile = (function(){ var cache = [], timer = null; return function(id){ cache.push(id); if(timer){ return } timer = setTimeout(function(){ syncFile(cache.join(",")) clearTimeout(timer); timer = null; cache = []; },2000) } })() //綁定事件 for(var i = 0;i<fileObjArr.length;i++){ fileObjArr[i].onclick = function(){ if(this.checked === true){ proxyFile(id) } } }
這樣,有選中操做的話,不會頻繁觸發請求。app
緩存代理能夠爲一些開銷大的運算結果提供暫時的存儲,在下次運算時,若是傳遞進來的參數跟以前一致, 則能夠返回前面的運算結果。 示例: 爲乘法、加法等建立緩存代理
// 計算乘積 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 += arguments[i]; } return a; }; // 建立緩存代理的工廠 var createProxyFactory = function( fn ){ var cache = {}; // 緩存 - 存放參數和計算後的值 return function(){ var args = Array.prototype.join.call(arguments, "-"); if( args in cache ){ // 判斷出入的參數是否被計算過 console.log( "使用緩存代理" ); return cache[args]; } return cache[args] = fn.apply( this, arguments ); } }; // 建立代理 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