Proxy(代理模式)屬於結構型模式,經過訪問代理對象代替訪問原始對象,以得到一些設計上的便捷。前端
意圖:爲其餘對象提供一種代理以控制這個對象的訪問。git
若是看不懂上面的意圖介紹,沒有關係,設計模式須要在平常工做裏用起來,結合例子能夠加深你的理解,下面我準備了三個例子,讓你體會什麼場景下會用到這種設計模式。github
得到一個文本對象長度,必需要真正渲染出來,而渲染是比較耗時的,咱們可能只在某些場景下須要訪問文本對象長度,而更多時候只須要讀取文本內容,這兩種操做耗時是徹底不一樣的,如何作到業務層調用無感知,來優化執行耗時呢?typescript
代理模式能夠解決這個問題,咱們將業務層使用的文本對象替換爲代理對象,這個代理對象初始化並不渲染文本,而是在調用文本長度時才渲染。設計模式
某個大型系統開發完了,忽然要求增長代碼訪問權限體系,不一樣模塊對相同的底層對象擁有不一樣訪問權限,此時這個權限控制邏輯若是寫入底層對象,就違背了開閉原則,而對象自己的實現也再也不純粹,增長了維護成本,如何作到不修改對象自己,實現權限控制呢?前端框架
代理模式也能解決,將底層對象導出替換爲代理對象,由代理對象控制訪問權限便可。微信
Angular 或 Vue 這類前端框架採用雙向綁定視圖更新技術,即對象修改後,使用到的視圖會自動刷新,這就須要作到如下兩點:框架
問題是,在業務代碼使用對象與修改對象的地方插入這段邏輯,顯然會增長巨大的維護成本,如何作到業務層無感知呢?優化
代理模式能夠很好的解決這個問題,其實業務層拿到的對象已是代理對象了,它在被訪問與被修改時,都會執行固定的鉤子作視圖綁定與視圖刷新。spa
意圖:爲其餘對象提供一種代理以控制這個對象的訪問。
代理模式的意圖很容易理解,就是經過代理對象代替原始對象的訪問。
這只是代理模式的實現方式,代理模式真正的難點不在於理解它是如何工做的,而是理解哪些場景適合用代理,或者說建立了代理對象,怎麼用才能發揮它的價值。
在上面例子中,已經舉出了幾種常見代理使用場景:
使用時關係以下:
Subject 定義的是 RealSubject 與 Proxy 共用的接口,這樣任何使用 RealSubject 的地方均可以使用 Proxy。
RealSubject 指的是原始對象,Proxy 是一個代理實體。
關係圖中能夠看出,當客戶端要訪問 subject 時,第一層訪問的是 Proxy 代理,由這個代理將 realSubject 轉發給客戶端。
下面例子使用 typescript 編寫。
`// 對象 obj
const proxy = new Proxy(obj, {
get(target,key) {}
set(target,key,value) {}
})
`
JS 建立代理仍是蠻簡單的,代理能夠控制對象的全部成員屬性,包括成員變量與成員方法的訪問(get)與修改(set)。
代理模式會增長微弱的開銷,所以請不要將全部對象都變成代理,沒有意義的代理只會徒增程序開銷。
另外代理對象過多,也會致使調試困難,由於代理層的存在,咱們每每可能忽略這一層帶來的影響,致使忘記這個對象實際上是一個代理。
代理和繼承有足夠多的類似之處,繼承中,子類幾乎能夠人爲是對父類的代理,子類能夠重寫父類的方法。但代理和繼承仍是有區別的:
若是你沒有采用 new Proxy
這種 API 建立代理,而是採用繼承的方式實現,你會一會兒繼承這個類的全部方法,而作不到按需控制訪問權限的靈活效果,因此代理比繼承更加靈活。
JS 的 new Proxy
對應了 Java 動態代理模式,通常認爲動態代理比靜態代理更強大。
最後,還要重申那句話,代理模式理解與運用並不難,難就難在可否在恰當的場合想到它,雙向綁定幾乎是代理模式最好的例子。
討論地址是: 精讀《設計模式 - Proxy 代理模式》· Issue #291 · dt-fe/weekly
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證)