代理模式
定義
代理模式(Proxy Pattern
):給某一個對象提供一個代理或佔位符,並由代理對象來控制對原對象的訪問。
當無法直接訪問某個對象或訪問某個對象存在困難時可以通過一個代理對象來間接訪問,爲了保證客戶端使用的透明性,所訪問的真實對象與代理對象需要實現相同的接口。根據代理模式的使用目的不同,代理模式又可以分爲多種類型,例如保護代理、遠程代理、虛擬代理、緩衝代理等,它們應用於不同的場合,滿足用戶的不同需求。
- 遠程代理(
Remote Proxy
):爲一個位於不同的地址空間的對象提供一個本地的代理對象,這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中,遠程代理又稱爲大使(Ambassador)。 - 虛擬代理(
Virtual Proxy
):如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時纔會被真正創建。 - 保護代理(
Protect Proxy
):控制對一個對象的訪問,可以給不同的用戶提供不同級別的使用權限。 - 緩衝代理(
Cache Proxy
):爲某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以共享這些結果。 - 智能引用代理(
Smart Reference Proxy
):當一個對象被引用時,提供一些額外的操作,例如將對象被調用的次數記錄下來等。
場景
代理模式在開發過程用到很多,但是並不是直接在代碼中使用,而是各種框架和工具提供的,比如spring-aop、mockito、mybatis、spring feign client等等,這些工具的共同點都是簡化開發者使用代理模式的方式,可以通過配置的方式實現代理而不是使用硬編碼的方式實現代理,所以幾乎只有在寫一些公共工具的時候纔會考慮到代理,比如權限驗證框架等。
現在有一個權限驗證系統,不同用戶有不同的權限,可能增加新的權限,可以用代理模式來驗證用戶的權限。
UML類圖
代碼
proxy
示例:
public class TestProxy {
@Test
public void test() {
PermissionProxy proxy = new PermissionProxy(new DeletePermission());
proxy.execute(new User("Ashe", new HashSet<>(Arrays.asList("update", "delete"))), "target A");
proxy.execute(new User("Bob", null), "target A");
/*
Ashe execute delete on target A...
Bob has no delete permission...
*/
}
}
總結
代理模式有很多優點,包括符合開閉原則的低耦合、細節隱藏、增強擴展,基於不同類型的代理模式也各有優點:
- 遠程代理爲位於兩個不同地址空間對象的訪問提供了一種實現機制,可以將一些消耗資源較多的對象和操作移至性能更好的計算機上,提高系統的整體運行效率。
- 虛擬代理通過一個消耗資源較少的對象來代表一個消耗資源較多的對象,可以在一定程度上節省系統的運行開銷。
- 緩衝代理爲某一個操作的結果提供臨時的緩存存儲空間,以便在後續使用中能夠共享這些結果,優化系統性能,縮短執行時間。
- 保護代理可以控制對一個對象的訪問權限,爲不同用戶提供不同級別的使用權限。
但是代理模式可能會讓系統運行變慢,特別是在那些高併發並且對響應時間很敏感的場景下,比如Web應用,如果對沒個請求都做一次代理,代理類中有做了很多複雜的檢查和增強,那麼勢必會讓請求速度明顯變慢,所以準備使用代理模式的時候必須考慮到併發和響應速度。
代理模式的類型較多,不同類型的代理模式有不同的優缺點,它們應用於不同的場合:
- 當客戶端對象需要訪問遠程主機中的對象時可以使用遠程代理。
- 當需要用一個消耗資源較少的對象來代表一個消耗資源較多的對象,從而降低系統開銷、縮短運行時間時可以使用虛擬代理,例如一個對象需要很長時間才能完成加載時。
- 當需要爲某一個被頻繁訪問的操作結果提供一個臨時存儲空間,以供多個客戶端共享訪問這些結果時可以使用緩衝代理。通過使用緩衝代理,系統無須在客戶端每一次訪問時都重新執行操作,只需直接從臨時緩衝區獲取操作結果即可。
- 當需要控制對一個對象的訪問,爲不同用戶提供不同級別的訪問權限時可以使用保護代理。
- 當需要爲一個對象的訪問(引用)提供一些額外的操作時可以使用智能引用代理。