Android 設計模式 - 代理模式
1.定義
給某一個物件提供一個代 理,並由代理物件控制對原物件的引用,它是一種物件結構型模式。
2. 作用
在某些情況下,客戶不想或者不能直接引用一個物件,此時可以通過一個稱之為「代理」的第三者來實現間接引用。代理物件可以在客戶端和目標物件之間起到中介的作用,並且可以通過代理物件去掉客戶不能看到的內容和服務,或者新增客戶需要的額外服務。
3. 角色
- 抽象主題角色:聲明瞭真實主題和代理主題的共同介面;
- 代理主題角色:內部包含對真實主題的引用,可以在任何時候操作真實主題物件;
- 真實主題角色:定義代理角色所代表的真實物件,在真實主題角色中實現真實的業務操作,客戶端可以通過代理主題角色間接呼叫真實主題角色中定義的方法。
4. 實現
一到節假日,火車票就十分難買,於是各種搶票軟體盛行。我們把資訊交給服務商,然後軟體幫我們日夜不停地刷票,最後大概率會搶到車票。在這裡,提供搶票服務的人就是代理物件,幫助買票人搶票獲得佣金。買票的人是被代理物件,具有真實的購票需求。
下面就以搶票的例子來說明代理模式的使用。
代理的實現分為:
- 靜態代理:代理類是在編譯時完成的。也就是說 Java 編譯完成後代理類是一個實際的 class 檔案。
- 動態代理:代理類是在執行時生成的。也就是說 Java 編譯完之後並沒有實際的 class 檔案,而是在執行時動態生成的類位元組碼,並載入到 JVM 中。

類圖
首先來看靜態代理,這個比較容易理解。
- 定義抽象主題角色。
public interface ITicketBuyer { /** * 買票 */ void buyTicket(); }
- 定義真實主題角色,即需要買票的人。
public class RealBuyer implements ITicketBuyer { @Override public void buyTicket() { System.out.println("我要一張北京到上海的復興號商務座"); } }
- 定義代理主題角色,提供搶票服務的人,持有買票人的資訊。
public class ProxyBuyer implements ITicketBuyer { // 被代理物件,即真正要買票的人 private ITicketBuyer realBuyer; public ProxyBuyer(ITicketBuyer realBuyer) { this.realBuyer = realBuyer; } @Override public void buyTicket() { System.out.println("代理人來買票:"); realBuyer.buyTicket(); } }
動態代理,動態地建立代理類,代理物件所有的方法被轉發給一個稱為 InvocationHandler 的物件,此時呼叫被代理物件的方法即可實現代理。更多動態代理的知識,請參考「 代理模式及Java實現動態代理 」。
public class DynamicProxyBuyer implements InvocationHandler { // 被代理物件,即真正要買票的人 private ITicketBuyer ticketBuyer; public DynamicProxyBuyer(ITicketBuyer ticketBuyer) { this.ticketBuyer = ticketBuyer; } public ITicketBuyer createProxy() { return (ITicketBuyer) Proxy.newProxyInstance(ITicketBuyer.class.getClassLoader(), new Class[]{ITicketBuyer.class}, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("buyTicket".equals(method.getName())) { System.out.println("代理人來買票:"); } return method.invoke(ticketBuyer, args); } }
客戶類使用時,直接呼叫代理物件的方法,即可實現代理的目的。
public class ProxyTest { public static void main(String[] args) { // 靜態代理 ITicketBuyer realBuyer = new RealBuyer(); //ITicketBuyer proxyBuyer = new ProxyBuyer(realBuyer); //proxyBuyer.buyTicket(); // 動態代理 DynamicProxyBuyer dynamicProxyBuyer = new DynamicProxyBuyer(realBuyer); ITicketBuyer proxyBuyer = dynamicProxyBuyer.createProxy(); proxyBuyer.buyTicket(); } }
5. 優缺點
1. 優點:
協調呼叫者和被呼叫者,降低了系統的耦合;代理物件作為客戶端和目標物件之間的中介,起到了保護目標物件的作用
2. 缺點:
由於在客戶端和真實主題之間增加了代理物件,因此會造成請求的處理速度變慢;
實現代理模式需要額外的工作(有些代理模式的實現非常複雜),從而增加了系統實現的複雜度。
3. 使用場景:
當需要控制對原始物件的訪問時;當需要建立開銷非常大的物件時;當需要在訪問物件時附加額外操作時。
【附錄】

資料圖