JS代理模式《JavaScript設計模式與開發實踐》閱讀筆記

代理模式

代理模式是爲一個對象提供一個代用品或佔位符,以便控制對它的訪問。javascript

保護代理和虛擬代理

保護代理:當有許多需求要向某對象發出一些請求時,能夠設置保護代理,經過一些條件判斷對請求進行過濾。java

虛擬代理:在程序中能夠能有一些代價昂貴的操做。此時能夠設置虛擬代理去代爲執行,這裏的虛擬代理便會在適合的時候(須要用到的時候)纔去執行。設計模式

保護代理用於控制不一樣權限的對象對目標對象的訪問,但在JavaScript並不容易實現保護代理,由於咱們沒法判斷誰訪問了某個對象。而虛擬代理是最經常使用的一種代理模式。

虛擬代理實現圖片預加載

預加載圖片在Web開發中十分經常使用,其經過異步的方式加載圖片,利用一張loading圖片佔位。等圖片加載好以後把圖片填充到img節點中。緩存

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('loading.gif')
      img.src = src
    }
  }
})()

proxyImage.setSrc('realImage.jpg')
經過 proxyImage間接的訪問了 MyImageproxyImage控制了客戶對 MyImage的訪問,而且在此過程當中加入了一些額外的操做,好比在真正的圖片加載好以前,先把img節點的src設置爲一張loading圖片。

代理的意義

面向對象設計原則——單一職責原則。單一職責原則指的是,就一個類(一般也包括對象和函數等)而言,應該僅有一個引發它變化的緣由。若是一個對象承擔了多項職責,就意味着這個對象將變得巨大,引發它變化的緣由會有多個。面向對象設計鼓勵將行爲分佈到細粒度的對象之中,若是一個對象承擔的職責過多,等於把這些職責耦合到了一塊兒,這種耦合會致使脆弱和低內聚的設計,帶變化發生時,設計可能會遭到意外的破壞。

虛擬代理例子中,代理模式給系統添加了額外的功能,預加載圖片。而咱們實際須要的只是MyImagesetImage方法。預加載只是一個錦上添花的功能。經過代理模式使得這兩個功能獨立開來,遵循了開放-封閉原則。app

緩存代理

緩存代理能夠爲一些開銷大的運算結果提供暫時的存儲,在下次運算時,若是傳遞進來的參數跟以前一致,則能夠直接返回前面存儲的運算結果。

乘積運算的例子異步

/*******計算乘積******/
var mult = function(){
  console.log('開始計算乘積')
  var a = 1 
  for (var i = 0,l = arguments.length;i<l;i++){
    a = a*arguments[i]
  }
  return a
}

/********乘積代理函數********/
var proxyMult = (function(){
  var cache = {} // 緩存對象
  return function(){
    var args = Array.prototype.join.call(arguments,',') // 將參數轉化成字符串做爲cache的key
    if (args in cache){
        // 若是cache對象中存儲了一樣的參數,直接返回對應的運算結果
        console.log('緩存結果:')
      return cache[args]
    }
      // 若是沒有該運算參數,保存新的參數和結果,並調用mult方法返回運算結果。
    return cache[args] = mult.apply(this, arguments)
  }
})()

console.clear()
console.log(proxyMult(1,2,3,4,5)) // mult運算
console.log(proxyMult(1,2,3,4,5)) // 讀取緩存結果
console.log(proxyMult(1,2,3,4)) // mult運算
console.log(proxyMult(1,2,3,4)) // 讀取緩存結果

/*******建立緩存代理的工廠函數*******/
var createProxyFactory = function(fn){
  var cache = {}
  return function(){
    var args = Array.prototype.join.call(arguments,',')
    if(args in cache){
      return cache[args]
    }
    return cache[args] = fn.apply(this, arguments)
  }
}
var proxyMult = createProxyFactory(mult)
console.log(proxyMult(12,3,4,5,6))
console.log(proxyMult(12,3,4,5,6))

最後

雖然代理模式很是有用,但咱們在編寫業務代碼的時候,每每不須要去預先猜想是否須要使用代理模式。當真正發現不方便直接訪問某個對象的時候,再編寫代理不遲。

代理模式是一種很實用的設計模式,很好的詮釋了面向對象中的單一職責原則和開放-封閉原則。在實際開發的時候每每會迫於進度壓力或者實現了再說的態度忽略了一些必要的代碼的可維護性,我以爲在一些簡單的地方去試着遵循一些設計理念是對本身代碼能力的提高。固然不要爲了設計而設計啦。函數

Done is better then Perfectthis

參考

《JavaScript設計模式與開發實踐》—— 曾探prototype

相關文章
相關標籤/搜索