設計模式之代理模式

1.代理模式。在某些情況下,出于種種考慮/限制,一個對象不能直接訪問另一個對象,需要一個第三者(代理)牽線搭橋從而間接達到訪問目的,這樣的模式就是代理模式。
2.業(yè)務開發(fā)中最常見的四種代理類型
(1)事件代理
用代理模式實現(xiàn)多個子元素的事件監(jiān)聽

// 獲取父元素
const father = document.getElementById('father')

// 給父元素安裝一次監(jiān)聽函數(shù)
father.addEventListener('click', function(e) {
    // 識別是否是目標子元素
    if(e.target.tagName === 'A') {
        // 以下是監(jiān)聽函數(shù)的函數(shù)體
        e.preventDefault()
        alert(`我是${e.target.innerText}`)
    }
} )

在這種做法下,我們的點擊操作并不會直接觸及目標子元素,而是由父元素對事件進行處理和分發(fā)、間接地將其作用于子元素,因此這種操作從模式上劃分屬于代理模式。
(2)虛擬代理
圖片預加載

class PreLoadImage {
    constructor(imgNode) {
        // 獲取真實的DOM節(jié)點
        this.imgNode = imgNode
    }
     
    // 操作img節(jié)點的src屬性
    setSrc(imgUrl) {
        this.imgNode.src = imgUrl
    }
}

class ProxyImage {
    // 占位圖的url地址
    static LOADING_URL = 'xxxxxx'

    constructor(targetImage) {
        // 目標Image,即PreLoadImage實例
        this.targetImage = targetImage
    }
    
    // 該方法主要操作虛擬Image,完成加載
    setSrc(targetUrl) {
       // 真實img節(jié)點初始化時展示的是一個占位圖
        this.targetImage.setSrc(ProxyImage.LOADING_URL)
        // 創(chuàng)建一個幫我們加載圖片的虛擬Image實例
        const virtualImage = new Image()
        // 監(jiān)聽目標圖片加載的情況,完成時再將DOM上的真實img節(jié)點的src屬性設置為目標圖片的url
        virtualImage.onload = () => {
            this.targetImage.setSrc(targetUrl)
        }
        // 設置src屬性,虛擬Image實例開始加載圖片
        virtualImage.src = targetUrl
    }
}

PreLoadImage 專心去做 DOM 層面的事情(真實 DOM 節(jié)點的獲取、img 節(jié)點的鏈接設置).
ProxyImage 幫我們調(diào)度了預加載相關的工作,我們可以通過 ProxyImage 這個代理,實現(xiàn)對真實 img 節(jié)點的間接訪問,并得到我們想要的效果。
在這個實例中,virtualImage 這個對象是一個“幕后英雄”,它始終存在于 JavaScript 世界中、代替真實 DOM 發(fā)起了圖片加載請求、完成了圖片加載工作,卻從未在渲染層面拋頭露面。因此這種模式被稱為“虛擬代理”模式。
(3)緩存代理
應用于一些計算量較大的場景里。在這種場景下,我們需要“用空間換時間”——當我們需要用到某個已經(jīng)計算過的值的時候,不想再耗時進行二次計算,而是希望能從內(nèi)存里去取出現(xiàn)成的計算結果。這種場景下,就需要一個代理來幫我們在進行計算的同時,進行計算結果的緩存了。
(4)保護代理
Proxy,它本身就是為攔截而生的,所以我們目前實現(xiàn)保護代理時,考慮的首要方案就是 ES6 中的 Proxy。
Proxy可以理解成,在目標對象之前架設一層攔截,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。

let obj = new Proxy({},{
  get:function(target,propKey,receiver){
    console.log(`getting ${propKey}!`)
    return Reflect.get(target, propKey, receiver)
  },
  set: function(target, propKey,value,receiver){
    console.log(`setting ${propKey}!`)
    return Reflect.set(target, propKey, value, receiver)
  }
})

obj.count = 1
//  setting count!
console.log(++obj.count)
//  getting count!
//  setting count!
//  2

3.代理模式的目的是十分多樣化的,既可以是為了加強控制、拓展功能、提高性能,也可以僅僅是為了優(yōu)化我們的代碼結構、實現(xiàn)功能的解耦。無論是出于什么目的,這種模式的套路就只有一個—— A 不能直接訪問 B,A 需要借助一個幫手來訪問 B,這個幫手就是代理器。需要代理器出面解決的問題,就是代理模式發(fā)光發(fā)熱的應用場景。

參考:JavaScript設計模式之代理模式1
JavaScript設計模式之代理模式2
阮一峰 proxy

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

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

  • 一、概述 ??代理模式我們接觸的就比較多了,所謂的代理模式就是,給某一個對象提供一個代理對象,并由代理對象控制對原...
    騎著烏龜去看海閱讀 1,009評論 0 9
  • 目錄 本文的結構如下: 引言 什么是代理模式 模式的結構 典型代碼 代理模式分類 代碼示例 代理模式和裝飾者模式的...
    w1992wishes閱讀 1,641評論 0 13
  • 1 代理模式的定義 代理模式:代理模式又叫委托模式,是為某個對象提供一個代理對象,并且由代理對象控制對原對象的訪問...
    Jerry_1116閱讀 20,808評論 3 10
  • 代理模式(Proxy Pattern) 在有些情況下,一個客戶不能或者不想直接訪問另一個對象,這時需要找一個中介幫...
    Acton_zhang閱讀 221評論 0 1
  • 游戲 書中用游戲來引入代理模式,游戲大家都玩過,基本套路就是打怪升級,我們把這段打游戲的過程系統(tǒng)化,非常簡單的一個...
    stayiwithime閱讀 1,030評論 0 0

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