設計模式之代理模式(上) 靜態代理與JDK動態代理

代理模式

  • 給某一個對象提供一個代理,並由代理對象控制對原對象的引用。

靜態代理

靜態代理是由咱們編寫好的類,在程序運行以前就已經編譯好的的類,此時就叫靜態代理。 說理論仍是比較懵逼的,直接上代碼:java

抽象主題,能夠想象成咱們的業務接口。設計模式

/**
 * 抽象主題。
 * @author wushuaiping
 * @date 2018/3/13 下午10:13
 */
public interface ISubject {

    /**
     *  好比如今有個業務功能,須要開啓某項校驗。
     */
    void enableCheck();
}

真實主題,能夠想象成咱們對業務接口的實現類。學習

/**
 *  真實主題
 * @author wushuaiping
 * @date 2018/3/13 下午10:21
 */
public class RealSubject implements ISubject {

    public void enableCheck() {
        System.out.println("我開啓了某項校驗~~");
    }
}

可是有一天,我忽然想加個日誌記錄,可是我不想去改動原有的方法。那麼咱們就可使用這種方式:測試

/**
 *  代理類
 * @author wushuaiping
 * @date 2018/3/13 下午10:23
 */
public class ProxySubject implements ISubject{

    private ISubject subject;

    public ProxySubject(ISubject subject){
        super();
        this.subject = subject;
    }

    // 對被代理對象的方法進行加強
    public void enableCheck() {
        before();
        subject.enableCheck();
        after();
    }

    private void before(){
        System.out.println("我記錄一下啓動校驗前的相關日誌。");
    }

    private void after(){
        System.out.println("我記錄一下啓動校驗後的相關日誌。");
    }
}

咱們使用靜態代理後,來試試看這種方式能不能行?測試代碼:this

public class Main{
    public static void main(String[] args) throws ApiException {
        ProxySubject proxy = new ProxySubject(new RealSubject());
        proxy.enableCheck();
    }
}

運行結果:設計

我記錄一下啓動校驗前的相關日誌
我開啓了某項校驗~~
我記錄一下啓動校驗後的相關日誌。

靜態代理模式相對比較簡單,可是缺點確定也是有的:代理

  1. 一個代理對象只能服務於一個類。若是有不少類須要記錄日誌的話,你的一個一個去實現。。累不死你。。日誌

  2. 代理對象必須實現接口,如上。一個字:仍是累。code

動態代理

這裏動態代理使用的是JDK的動態代理實現的,JDK的動態代理必須是目標對象實現接口才能夠。也就是至關於咱們上面的業務實現類(RealSubject)。使用CGLIB就不用實現接口也可完成動態代理,可是今天時間很少了,明天還得搬磚,因此先把JDK動態代理學了,明天再學學CGLIB的動態代理。 代碼以下:對象

要實現動態代理;須要先去實現InvocationHandler接口,這個接口提供了invoke方法,該方法相信用過反射或者AOP的同窗應該都比較熟悉,我這裏就很少講了。實現了這個後咱們能夠調用目標方法了,可是咱們須要代理的對象還不知道從何而來,因此咱們還須要使用JDK提供的Proxy.newProxyInstance方法,第一個參數是目標代理類的類加載器,第二個參數是目標代理類實現的接口,第三個參數的話是目標代理類的調用處理程序就是InvokeHandler啦。用該方法能夠生產代理對象。

/**
 *  使用Java的動態代理實現
 * @author wushuaiping
 * @date 2018/3/13 下午10:43
 */
public class DynamicProxy implements InvocationHandler {

    private Object target;

    public Object getProxyInstance(Object target){
        this.target = target;
        // 使用Java的獲取代理實例方法來獲取代理實例。。好繞啊。。反正就是獲取代理實例-_-
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);

    }
    // 加強, 調用目標方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        // 由於咱們須要被加強的方法enableCheck是沒有返回參數的,因此不須要返回值。
        // 若是有返回值 Object res = method.invoke(proxy, args); return res;就能夠了
        method.invoke(target, args);
        after();
        return null;
    }

    private void before(){
        System.out.println("操做以前的日誌記錄~~");
    }

    private void after(){
        System.out.println("操做以後的日誌記錄~~");
    }
}

Test case

public static void main(String[] args) throws ApiException {
        DynamicProxy proxy = new DynamicProxy();
        ISubject subject = (ISubject)proxy.getProxyInstance(new RealSubject());
        subject.enableCheck();
    }

運行結果:

操做以前的日誌記錄~~
我開啓了某項校驗~~
操做以後的日誌記錄~~

今天的設計模式算是學完啦,抽象工廠模式感受我可能思惟不夠抽象,因此到如今還沒能理解抽象工廠模式到底能幹嗎?實際中有何用處?本文用於我的學習記錄,有寫的很差的地方,還請各位大佬指點一二!

good night!

相關文章
相關標籤/搜索