設計模式 —— 代理模式(Proxy Pattern)
代理模式(Proxy Pattern)
概念:
定義:代理模式 為另一個物件提供一個替身或佔位符以控制這個物件的訪問。
代理模式很好理解,在生活中也很常見。舉個簡單的例子,我們自己能做很多事情(動作),比如寫作業,出去玩等。當我們和父母在家的時候,同學叫我們出去玩,父母先收到訊息,然後忽略掉出去玩的資訊。如果同學叫我們去寫作業,父母接收到後在傳達給我們。此時父母就是我們的代理,並且對我們 資源 進行了一定的控制,這是代理模式的一種:保護代理。
使用代理模式建立代表物件,讓代表物件控制某物件的訪問,被代理的物件可以是 遠端的物件、建立開銷大的物件 或 需要安全控制 的物件。
常見的代理模式有 3 種:
遠端代理:控制訪問遠端物件。
虛擬代理:控制訪問建立開銷大的資源。
保護代理:基於許可權控制對資源的訪問。
組成:
Subject(介面):Proxy 和 RealSubject 物件都實現 Subject 介面,這使得任何客戶端都可以像處理 Proxy 一樣處理 RealSubject。
Proxy(代理物件):代理物件持有 RealSubject(真實物件)的引用,必要時可以將請求轉發給 Subject。
RealSubject(真實物件):真實物件通常是真正做事情的物件,Proxy 可以控制對 RealSubject 物件的訪問。
例子:
現在有一位明星,他有很多個人資訊,而他的經紀人就是他的代理。經紀人會隱藏很多明星的資訊,如年齡、身高等。
介面類:包含明星和代理都要實現的方法。
public interface PersonBean {
String getName();
String getInteresters();
int getAge();
double getHeight();
void setName(String name);
void setInteresters(String interesters);
void setAge(int age);
void setHeight(int height);
}
明星類:
public class Star implements PersonBean {
private String name;
private String interesters;
private int age;
private double height;
public String getName() {
return name;
}
public String getInteresters() {
return interesters;
}
public int getAge() {
return age;
}
public double getHeight() {
return height;
}
public void setName(String name) {
this.name = name;
}
public void setInteresters(String interesters) {
this.interesters = interesters;
}
public void setAge(int age) {
this.age = age;
}
public void setHeight(int height) {
this.height = height;
}
}
經紀人類:
public class ProxyPeoson implements PersonBean{
private PersonBean star;
public ProxyPeoson(PersonBean star) {
this.star = star;
}
public String getName() {
return star.getName();
}
public String getInteresters() {
return star.getInteresters();
}
//修改明星的年齡
public int getAge() {
return star.getAge()-5;
}
//修改明星的身高
public double getHeight() {
return star.getHeight()+10;
}
public void setName(String name) {
star.setName(name);
}
public void setInteresters(String interesters) {
star.setInteresters(interesters);
}
public void setAge(int age) {
star.setAge(age);
}
public void setHeight(int height) {
star.setHeight(height);
}
}
測試類:
public class ProxyTest {
public static void main(String[] args) {
Star star = new Star();
ProxyPeoson proxyPeoson = new ProxyPeoson(star);
star.setName("Tom");
star.setInteresters("basketball");
star.setAge(32);
star.setHeight(174);
//明星姓名和興趣不會變。
System.out.println("Star Name:" + proxyPeoson.getName());
//經紀人會隱藏明星的年齡,比實際年齡小 5 歲
System.out.println("Star Age:" + proxyPeoson.getAge());
//經紀人會應藏明星的身高,比實際身高高 10 cm
System.out.println("Star Height:" + proxyPeoson.getHeight());
System.out.println("Star Intersters:" + proxyPeoson.getInteresters());
}
}
其實上面例子是 保護代理 的演示,比如明星某些隱私不能讓大眾知道,那麼經紀人就會拒絕告知。
如果上面的例子改為:明星不在時,他的一切事務全由經紀人代理,如果真的某些事情必須明星出面在找到他(例項化),這就是所謂的 虛擬代理,直到真正需要一個物件時才建立它。
如果上面的例子改為:明星不在,但通過網路和經紀人取得聯絡,互相通訊事務,經紀人遇到情況會通過網路轉發給明星,明星執行完後返回給經濟人,這就是所謂的 遠端代理,呼叫代理的方法,會被代理利用網路轉發到遠端執行,並且結果會通過網路返回到代理,再由代理將結果轉給客戶。
適用場景:
- 遠端代理(Remote Proxy):為一個位於不同的地址空間的物件提供一個本地的代理物件。這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中。
- 虛擬代理(Virtual Proxy):根據需要建立開銷很大的物件。如果需要建立一個資源消耗較大的物件,先建立一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正建立。
- 保護代理(Protection Proxy):控制對原始物件的訪問。保護代理用於物件應該有不同的訪問許可權的時候。
優缺點:
優點:
- 代理模式能夠協調呼叫者和被呼叫者,在一定程度上降低了系統的耦合度。
缺點:
- 由於在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢。
- 實現代理模式需要額外的工作,有些代理模式的實現非常複雜。
與其它模式區別:
介面卡模式 Adapter:介面卡模式為它所適配的物件提供了一個不同的介面。相反,代理提供了與它的實體相同的介面。然而,用於訪問保護的代理可能會拒絕執行實體會執行的操作,因此,它的介面實際上可能只是實體介面的一個子集。
裝飾器模式 Decorator:儘管Decorator的實現部分與代理相似,但 Decorator 的目的不一樣。Decorator 為物件新增一個或多個功能,而代理則控制對物件的訪問。