java設計模式——代理模式(Proxy Pattern)
阿新 • • 發佈:2019-02-02
概述:
在某些情況下,一個客戶不想或者不能直接引用一個對 象,此時可以通過一個稱之為“代理”的第三者來實現 間接引用。代理物件可以在客戶端和目標物件之間起到 中介的作用,並且可以通過代理物件去掉客戶不能看到 的內容和服務或者新增客戶需要的額外服務。通過引入一個新的物件來實現對真實物件的操作或者將新的對 象作為真實物件的一個替身,這種實現機制即 為代理模式。代理模式又可以分為多種型別,例如保護代理、遠端代理、虛擬代理、緩衝代理等,它們應用於不同的場合,滿足使用者的不同需求。
定義:
代理模式(Proxy Pattern) :給某一個物件提供一個代理,並由代理物件控制對原物件的引用。代理模式的英文叫做Proxy或Surrogate,它是一種物件結構型模式。
結構:
場景:小張和小明是好基友,小張喜歡上了隔壁班裡的班花,於是寫了一封情書,讓小明幫忙拿給班花,小明很爽快的答應了,當小明找到那個班花的時候,發現挺漂亮的,正好找到機會將情書遞給班花,結果小明跟班花一起了,後來小明跟小張友盡。。。ps:這個故事是我聽坐在輪椅上面的小明說的。。。 程式碼分析: /**
* Created by **
* 抽象角色
*/
public abstract class Subject {
// 寫情書
public abstract void WriteLoveLetter();
}
/**
* Created by **
* 真實角色:小張
*/
public class RealSubject extends Subject {
private final String TAG = "test";
@Override
public void WriteLoveLetter() {
Log.d(TAG,"**自從見到你之後就情不自禁的愛上你了...");
}
}
/**
* Created by **
* 代理角色:小明,幫小張送情書的
*/
public class ProxySubject extends Subject {
private final String TAG = "test";
private RealSubject realSubject;
public ProxySubject(){
this.realSubject = new RealSubject();
}
@Override
public void WriteLoveLetter() {
submitLetter("班花");
realSubject.WriteLoveLetter();
afterward();
}
/**
* 將情書交給班花(相當於 preRequest())
*/
private boolean submitLetter(String string){
if ("班花".equals(string)){
Log.d(TAG,"找到隔壁班花,將情書給她");
return true;
}else {
Log.d(TAG,"找錯人了!!!");
}
return false;
}
/**
* 將情書交給班花之後,班花跟小明一起了...(相當於 afterRequest())
*/
private void afterward(){
Log.d(TAG,"班花以為是小明喜歡她,跟小明一起了");
}
}
客戶端: ProxySubject proxySubject = new ProxySubject();
proxySubject.WriteLoveLetter();
log輸出: 08-11 16:49:10.874 5020-5020/? D/test: 找到隔壁班花,將情書給她 08-11 16:49:10.884 5020-5020/? D/test: **自從見到你之後就情不自禁的愛上你了... 08-11 16:49:10.884 5020-5020/? D/test: 班花以為是小明喜歡她,跟小明一起了 上面這個例子,相當於一個保護代理,submitLetter() 這個方法負責進行身份驗證,當然我這裡寫得比較簡單,實際開發工程中需要根據實際情況進行程式碼開發。 程式碼寫完之後發現跟裝飾模式太像了,UML圖也非常相似,不過仔細對比一下還是能找出兩者區別: 裝飾器模式:能動態的新增或組合物件的行為。 代理模式:為其他物件提供一種代理以控制對這個物件的訪問. 裝飾模式是“新增行為”,而代理模式是“控制訪問”。關鍵就是我們如何判斷是“新增行為”還是“控制訪問”。 優點:
- Subject(抽象主題角色):它聲明瞭真實主題和代理主題的共同介面,這樣一來在任何使用真實主題的地方都可以使用代理主題,客戶端通常需要針對抽象主題角色進行程式設計。
- Proxy(代理主題角色):它包含了對真實主題的引用,從而可以在任何時候操作真實主題物件;在代理主題角色中提供一個與真實主題角色相同的介面,以便在任何時候都可以替代真實主題;代理主題角色還可以控制對真實主題的使用,負責在需要的時候建立和刪除真實主題物件,並對真實主題物件的使用加以約束。通常,在代理主題角色中,客戶端在呼叫所引用的真實主題操作之前或之後還需要執行其他操作,而不僅僅是單純呼叫真實主題物件中的操作。
- RealSubject(真實主題角色):它定義了代理角色所代表的真實物件,在真實主題角色中實現了真實的業務操作,客戶端可以通過代理主題角色間接呼叫真實主題角色中定義的操作。
場景:小張和小明是好基友,小張喜歡上了隔壁班裡的班花,於是寫了一封情書,讓小明幫忙拿給班花,小明很爽快的答應了,當小明找到那個班花的時候,發現挺漂亮的,正好找到機會將情書遞給班花,結果小明跟班花一起了,後來小明跟小張友盡。。。ps:這個故事是我聽坐在輪椅上面的小明說的。。。 程式碼分析: /**
* Created by **
* 抽象角色
*/
public abstract class Subject {
// 寫情書
public abstract void WriteLoveLetter();
}
/**
* Created by **
* 真實角色:小張
*/
public class
private final String TAG = "test";
@Override
public void WriteLoveLetter() {
Log.d(TAG,"**自從見到你之後就情不自禁的愛上你了...");
}
}
/**
* Created by **
* 代理角色:小明,幫小張送情書的
*/
public class ProxySubject extends Subject {
private final String TAG = "test";
private RealSubject realSubject;
public ProxySubject(){
this.realSubject = new RealSubject();
}
@Override
public void WriteLoveLetter() {
submitLetter("班花");
realSubject.WriteLoveLetter();
afterward();
}
/**
* 將情書交給班花(相當於 preRequest())
*/
private boolean submitLetter(String string){
if ("班花".equals(string)){
Log.d(TAG,"找到隔壁班花,將情書給她");
return true;
}else {
Log.d(TAG,"找錯人了!!!");
}
return false;
}
/**
* 將情書交給班花之後,班花跟小明一起了...(相當於 afterRequest())
*/
private void afterward(){
Log.d(TAG,"班花以為是小明喜歡她,跟小明一起了");
}
}
客戶端: ProxySubject proxySubject = new ProxySubject();
proxySubject.WriteLoveLetter();
log輸出: 08-11 16:49:10.874 5020-5020/? D/test: 找到隔壁班花,將情書給她 08-11 16:49:10.884 5020-5020/? D/test: **自從見到你之後就情不自禁的愛上你了... 08-11 16:49:10.884 5020-5020/? D/test: 班花以為是小明喜歡她,跟小明一起了 上面這個例子,相當於一個保護代理,submitLetter() 這個方法負責進行身份驗證,當然我這裡寫得比較簡單,實際開發工程中需要根據實際情況進行程式碼開發。 程式碼寫完之後發現跟裝飾模式太像了,UML圖也非常相似,不過仔細對比一下還是能找出兩者區別: 裝飾器模式:能動態的新增或組合物件的行為。 代理模式:為其他物件提供一種代理以控制對這個物件的訪問. 裝飾模式是“新增行為”,而代理模式是“控制訪問”。關鍵就是我們如何判斷是“新增行為”還是“控制訪問”。 優點:
- 能夠協調呼叫者和被呼叫者,在一定程度上降低了系統的耦合度。
- 客戶端可以針對抽象主題角色進行程式設計,增加和更換代理類無須修改原始碼,符合開閉原則,系統具有較好的靈活性和可擴充套件性。
- 遠端代理為位於兩個不同地址空間物件的訪問提供了一種實現機制,可以將一些消耗資源較多的物件和操作移至效能更好的計算機上,提高系統的整體執行效率。
- 虛擬代理通過一個消耗資源較少的物件來代表一個消耗資源較多的物件,可以在一定程度上節省系統的執行開銷。
- 緩衝代理為某一個操作的結果提供臨時的快取儲存空間,以便在後續使用中能夠共享這些結果,優化系統性能,縮短執行時間。
- 保護代理可以控制對一個物件的訪問許可權,為不同使用者提供不同級別的使用許可權。
- 由於在客戶端和真實主題之間增加了代理物件,因此 有些型別的代理模式可能會造成請求的處理速度變慢。
- 實現代理模式需要額外的工作,有些代理模式的實現 非常複雜。
- 遠端(Remote)代理:為一個位於不同的地址空間的物件提供一個本地 的代理物件,這個不同的地址空間可以是在同一臺主機中,也可是在 另一臺主機中,遠端代理又叫做大使(Ambassador)。
- 虛擬(Virtual)代理:如果需要建立一個資源消耗較大的物件,先建立一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正建立。
- Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲 到只有在客戶端真正需要時才執行。一般來說,物件的深克隆是一個 開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有物件被用到的時候才被克隆。
- 保護(Protect or Access)代理:控制對一個物件的訪問,可以給不同的使用者提供不同級別的使用許可權。
- 緩衝(Cache)代理:為某一個目標操作的結果提供臨時的儲存空間,以便多個客戶端可以共享這些結果。
- 防火牆(Firewall)代理:保護目標不讓惡意使用者接近。
- 同步化(Synchronization)代理:使幾個使用者能夠同時使用一個物件而沒有衝突。
- 智慧引用(Smart Reference)代理:當一個物件被引用時,提供一些額外的操作,如將此物件被呼叫的次數記錄下來等。