Java設計模式之代理模式

前言

代理模式也被稱爲委託模式,它是結構型設計模式的一種。在現實生活中我們用到類似代理模式的場景有很多,比如代理上網、打官司等。

定義

爲其他對象提供一種代理以控制對這個對象的訪問。

角色

  • Subject:抽象主題類,聲明真實主題與代理的共同接口方法。
  • RealSubject:真實主題類,代理類所代表的真實主題。客戶端通過代理類間接地調用真實主題類的方法。
  • Proxy:代理類,持有對真實主題類的引用,在其所實現的接口方法中調用真實主題類中相應的接口方法執行。
  • client:客戶端類。

類型

從編碼角度分類

  • 靜態代理
  • 動態代理

從適用範圍分類

  • 遠程代理:爲一個對象在不同的地址空間提供局部代表,這樣系統可以將 Server 部分的實現隱藏。
  • 虛擬代理:使用一個代理對象表示一個十分耗資源的對象並在真正需要是才創建。
  • 安全代理:用來控制真實對象訪問的權限。一般用於真實對象有不同的訪問權限時。
  • 智能指引:當調用真實的對象時,代理處理另外一些事,比如計算機真實對象的引用計數,當該對象沒有引用時,可以自動釋放它;或者訪問一個實際對象時,檢查是否已經能夠鎖定它,以確保其他對象不能改變它。

靜態代理模式的簡單實現

場景描述

我多年沒有回哈爾濱了,很想念哈爾濱的秋林紅腸味道。但是本人因爲工作一直很忙抽不開身,不能夠親自回哈爾濱購買,於是就拜託在哈爾濱的朋友幫我購買秋林紅腸。

  1. 抽象主題類:抽象主題類具有真實主題類和代理的共同接口方法 buy
public interface IShop {
    void buy();
}
  1. 真實主題類:這個購買者 Giants 就是我,實現了 IShop 接口提供的 buy 方法。
public class Giants implements IShop {
    @Override
    public void buy() {
        System.out.println("購買");
    }
}
  1. 代理類:我找的代理類同樣也要實現 IShop 接口,並且要持有被代理者,在 buy 方法中調用了被代理者的 buy 方法。
public class Purchasing implements IShop {
    private IShop mShop;

    public Purchasing(IShop shop) {
        this.mShop = shop;
    }

    @Override
    public void buy() {
        mShop.buy();
    }
}
  1. 客戶端類:客戶端類的代碼就是包含了真實主題類(被代理者),最終調用的都是真實主題類(被代理者)實現的方法。
public class Client {
    public static void main(String[] args) {
        IShop giants = new Giants();
        IShop purchasing = new Purchasing(giants);
        purchasing.buy();
    }
}

動態代理模式的簡單實現

場景描述

上面的例子是一個靜態的代理,在代碼運行前已經存在了代理類的 class 編譯文件;而動態代理則是在帶來運行時通過反射來動態地生成代理類的對象,並確定到底代理誰。我們在編碼階段無需知道代理誰,代理誰將會在代碼運行時覺定。

  1. 創建動態代理類
/**
 * 實現Java提供的動態代理接口 InvocationHandler ,實現該接口需要重寫 invoke 方法
 */
public class DynamicPurchasing implements InvocationHandler {
    private Object obj;

    public DynamicPurchasing(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(obj, args);
        if(method.getName().equals("buy")){
            System.out.println("Giants在買買買");
        }
        return result;
    }
}
  1. 修改客戶端類代碼如下:調用 Proxy.newProxyInstance 來生成動態代理類,調用 purchasingbuy 方法會調用 mDynamicPurchasinginvoke 方法。
public class Client {
    public static void main(String[] args) {
        //創建 Giants
        IShop giants = new Giants();
        //創建動態代理
        DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(giants);
        //創建 giants 的 ClassLoader
        ClassLoader loader = giants.getClass().getClassLoader();
        //動態創建代理類
        IShop purchasing = (IShop) Proxy.newProxyInstance(loader, new Class[] {IShop.class}, mDynamicPurchasing);
        purchasing.buy();
    }
}

優點

  • 真實主題類就是實現實際的業務邏輯,不用關心其他非本職工作。
  • 真實主題類隨時都會發生變化;但是因爲它實現了公共的接口,所以代理類可以不做任何修改就能夠使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章