Android小知識-剖析Retrofit前的預備知識(靜態代理與動態代理)

顧林海發表於2019-02-26

本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝!

代理設計模式主要分為靜態代理與動態代理,代理模式的定義是為其他物件提供一種代理,用以控制對這個物件的訪問。打個比方:你人在國內,但是想要購買國外的某件商品,這時候你可以找朋友幫你買,你朋友就是代理,至於你朋友怎麼買你不關心,你只要拿到商品就行。

靜態代理

image

看上面這張類圖,靜態代理需要三個角色,一個是抽象物件角色(AbstractObject),一個是目標物件角色(RealObject),最後是代理物件角色(ProxyObject),在抽象物件角色類中定義了目標物件和代理物件的共同介面,RealObject是代理物件所代理的目標物件,ProxyObject是代理物件角色,內部會持有目標物件角色的引用,這樣的話可以通過代理物件執行目標物件內的方法,接下來看具體的程式碼實現。

抽象物件角色:

public abstract class AbstractObject {
    protected abstract void operation();
}
複製程式碼

目標物件角色:

public class RealObject extends AbstractObject {
    @Override
    protected void operation() {
        System.out.println("目標物件的方法");
    }
}
複製程式碼

代理物件角色:

public class ProxyObject extends AbstractObject {

    private AbstractObject mRealObject;

    public ProxyObject(AbstractObject realObject){
        this.mRealObject=realObject;
    }

    @Override
    protected void operation() {
        System.out.println("執行目標物件前的工作....");
        this.mRealObject.operation();
        System.out.println("執行目標物件後的工作....");
    }
}
複製程式碼

在代理物件的operation方法中我們可以進行一些額外的操作,比如日誌的統計或者業務邏輯處理等。在日常開發中對已有的程式碼做改進,這時可以使用一個代理類對原有的結果進行控制。

動態代理

在Retrofit中使用到了動態代理,使用動態代理,可以無侵入式的擴充套件程式碼,在不改動原有程式碼的情況下,增強一些方法或功能,它的定義是:在程式執行時建立的代理方式。

接下來通過一個例項來了解動態代理:

public interface Subject {
    void operation();
}
複製程式碼

建立了一個Subject介面,它是代理類和被代理類共同實現的一個介面。

public class RealObject implements Subject {
    @Override
    public void operation() {
        System.out.println("目標物件的方法");
    }
}
複製程式碼

RealObject是被代理物件,內部operation方法執行被代理類原有的方法。

public class ProxyObject implements InvocationHandler {

    private Object mRealObject;

    public ProxyObject(Object realObject){
        this.mRealObject=realObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("operation".equals(method.getName())){
            System.out.println("哈哈,捕捉到operation方法,我要做點其他事情...");
            return  method.invoke(mRealObject,args);
        }
        return null;
    }
}
複製程式碼

ProxyObject就是代理類,mRealObject代表真實的物件,ProxyObject需要實現InvocationHandler介面,並實現invoke方法,方法內部第一個引數proxy表示被代理的真實物件,第二個引數method表示真實物件的方法,第三個引數args表示真實物件的方法的引數。

public class Test {
    public static void main(String[] args) {
        Subject subject=new RealObject();
        Subject proxyObject= (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
                new Class<?>[]{Subject.class},
                new ProxyObject(subject));
        proxyObject.operation();
    }
}
複製程式碼

通過Proxy的newProxyInstance方法建立代理類,傳入第一個引數是被代理類的ClassLoader,第二個引數是被代理實現的介面,第三個引數就是實現了InvocationHandler的物件。

執行結果:

哈哈,捕捉到operation方法,我要做點其他事情...
目標物件的方法
複製程式碼

在代理類ProxyObject的invoke方法中攔截到了operation方法,這時可以新增上我們需要的程式碼或功能。


838794-506ddad529df4cd4.webp.jpg

搜尋微信“顧林海”公眾號,定期推送優質文章。

相關文章