1. 程式人生 > >Java設計模式之—靜態代理和動態代理

Java設計模式之—靜態代理和動態代理

靜態代理

代理從字面意思來看就是,替代XX去做某事,在我們的程式中,一般替代實際物件去進行操作,扮演著中間人的角色:

客戶端 –> 業務類
客戶端 –> 代理 –>業務類(代理)

代理介面

interface Operation{
    void download();
}

實際物件(業務類)

class RealObject implements Operation{

    @Override
    public void download() {
        //進行邏輯操作
    }

}

代理類

class
ProxyObject implements Operation{
private Operation operation; public ProxyObject(Operation operation) { this.operation = operation; } @Override public void download() { operation.download();//通過代理來呼叫實際物件的方法 } }

主類

public class TestProxy {

    public
static void main(String[] args) { Operation operation = new ProxyObject(new RealObject());//把實際物件傳入代理 operation.download(); } }

代理的優點:業務類只需要關注業務本身,保證了程式碼的重用性。
代理的缺點:一個真實角色只能對應一個代理角色,要是真實角色多了,代理也隨著增多,會導致類的急劇膨脹。

場景描述

假設有這麼一個類:(在此簡化程式碼,但實際程式碼非常複雜)

class RealObject implements
Operation{
@Override public void download() { //我要測量這個方法所在的執行緒和花費的時間等,這個操作程式碼量可能為50行 } }

我需要做一些對這個類進行一些跟蹤的操作或者測量一下這個類的記憶體開銷,比如我想列印一下這個類的某個方法所在的執行緒和花費時間,這個類非常複雜,難道我要把這些操作整合到類中嗎?顯然不明智!

明智的做法是:使用代理

動態代理

場景描述

假設有這樣一個場景,你需要對某一個介面的方法進行擴充套件,這時你一般的選擇是:
實現介面,並重寫該方法!
但是我們知道,實現介面,則必須實現它所有的方法。方法少的介面倒還好,但是如果恰巧這個介面的方法有很多呢,例如List介面。
更好的選擇是:
使用動態代理!

代理的使用場景:

如果對某個介面中的某個指定的方法的功能進行擴充套件,新增額外的使用者邏輯,而不想實現接口裡所有方法,可以使用(動態)代理模式,監聽方法的執行!

下面是對一個List介面的isEmpty方法進行監聽:

public class TestProxy {

    @SuppressWarnings("unchecked")
    private static List<Integer> createProxy() {
        List<Integer> list = new ArrayList<>();
        List<Integer> proxy = (List<Integer>) Proxy.newProxyInstance(
                list.getClass().getClassLoader(),
                new Class[]{List.class}, 
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        Object result = null;

                        String methodName = method.getName();
                        if("isEmpty".equals(methodName)){//捕獲我們需要監聽的方法
                            System.out.println("你呼叫了isEmpty方法");
                        }else{
                            result = invoke(proxy, method, args);//執行方法
                        }
                        return result;//返回執行方法的結果
                    }
                });

        return proxy;//返回代理
    }

    public static void main(String[] args) {
        List<Integer> list = createProxy();
        list.isEmpty();
    }
}

結果為:

你呼叫了isEmpty方法

具體的步驟,註釋裡都很清楚,動態代理主要用到了Proxy的newProxyInstance(ClassLoader loader,Clas< ?>[] interfaces, InvocationHandler h)。
第一個引數:代理的類或介面的類載入器
第二個引數:代理的介面
第三個闡述:執行方法的Handler