1. 程式人生 > >java設計模式自我總結---代理模式

java設計模式自我總結---代理模式

代理模式是給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用,通俗的來講代理模式就是我們生活中常見的中介。

   Spring 的AOP面向切面就是使用動態代理模式來實現的;

   打個比方說:我要買房,但是我對該地區房屋的資訊掌握的不夠全面,希望找一個更熟悉的人(中介)去幫我找,此處的代理就是這個意思。

  代理類分為靜態代理類和動態代理類:

  首先看下靜態代理類,程式碼如下:

  介面:

public interface Source {
    void method();
}

  委託類:

/**
 * 委託類
 */
public class
RealSubject implements Source { @Override public void method() { System.out.println("我要去買房了"); } }

  1、靜態代理類:

/**
 * 靜態代理類
 */
public class ProxySubject implements Source{

    private RealSubject realSubject;

    public ProxySubject() {
        this.realSubject = new
RealSubject(); } @Override public void method() { before(); realSubject.method(); after(); } void before(){ System.out.println("找房"); } void after(){ System.out.println("買房後裝修"); } }

  測試類:

public class
Text { public static void main(String[] args) { Source source = new ProxySubject(); source.method(); } }

  輸出結果:

找房
我要去買房了
買房後裝修

  靜態代理總結:

優點:可以做到在符合開閉原則的情況下對目標物件進行功能擴充套件。

  缺點:我們得為每一個服務都建立代理類,工作量太大,不易管理。同時介面一旦發生改變,代理類也得相應修改。

   2、動態代理類

  動態代理類中我們不需要手動的建立代理類,我們只需要手動的編寫一個動態處理器就可以了,真正的代理物件由JDK在執行時為我們動態的進行建立;

Dynamic代理模式相對於靜態代理,大大減少了我們的開發任務,同時減少了對業務介面的依賴,降低了耦合度;

  動態代理的實現依靠於InvocationHandler介面和Proxy類來實現的,每一個動態代理類中都必須要實現InvocationHandler介面,該介面中有唯一的invoke()方法;

  該方法的作用就是得到一個動態的代理物件,其接收三個引數:

loader:  第一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入

interfaces:  第二個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了

h:  第三個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上

  我們來看一下程式碼:

  首先定義一個介面,有兩個方法

public interface Source {
    void describe();
    void buyHourse();
}

  給該介面定義一個實現類,其實就是我們的委託物件 

public class SourceImpl implements Source {
    @Override
    public void describe() {
        System.out.println("中國風");
    }
    @Override
    public void buyHourse() {
        System.out.println("購房");
    }
}

  定義動態代理類,注意一定要實現介面 InvocationHandler

public class DynamicProxy implements InvocationHandler{

    /**這個就是要代理的委託物件,使用Object型別,可以代理不同型別的物件,便於複用*/
    private Object source;

    /**構造器,給要代理的物件賦值*/
    public DynamicProxy(Object source) {
        this.source = source;
    }

    /*
    我的理解:當我們通過動態代理物件呼叫委託物件的方法時會執行該方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        /*當代理物件呼叫真實物件的方法時,其會自動的跳轉到代理物件關聯的handler物件的invoke方法來進行呼叫*/
        method.invoke(source,args);
        after();
        return null;
    }

    void before(){
        System.out.println("呼叫物件方法前執行的業務邏輯");
    }

    void after(){
        System.out.println("呼叫物件方法後執行的業務邏輯");
    }
}

  測試類

public class Test {
    public static void main(String[] args) {
        //要代理的真實物件
        Source realSource = new SourceImpl();
        //建立handler例項,我們要代理哪個物件就把該物件傳進去,最後通過該真是物件來呼叫其方法
        InvocationHandler handler = new DynamicProxy(realSource);
        /**
         * 通過Proxy.newProxyInstance方法來建立代理物件,
         * 第一個引數是目標物件的類載入器,獲取方法為geiClassLoader()
         * 第二個引數是一個Interface物件的陣列,表示的是將要給需要代理的物件提供一組什麼藉口,
         *     如果我提供了一組介面給它,那麼這個代理物件就可以實現該介面(多型),
         *     這樣就能呼叫這組介面中的方法了
         *     這裡我們為代理物件提供的介面是真實物件所實行的介面,表示要代理的是該真是物件,
         *     這樣就可以呼叫這組介面中的方法了
         * 第三個引數handler,指定的動態代理處理器,將該動態處理器傳入真實的代理物件,即委託類物件
         */
        Source source = (Source) Proxy.newProxyInstance(Source.class.getClassLoader(),
                realSource.getClass().getInterfaces(),handler);
        source.describe();
        System.out.println("");
        source.buyHourse();
    }
}

  輸出結果

呼叫物件方法前執行的業務邏輯
中國風
呼叫物件方法後執行的業務邏輯

呼叫物件方法前執行的業務邏輯
購房
呼叫物件方法後執行的業務邏輯

  OK,至此兩個常見的代理模式就到這裡了,明天說一下使用第三方外掛實現的CGLIB代理模式;下班了回家!!祝大家中秋節快樂!!!

持續更新中...

參考連結: https://www.cnblogs.com/daniels/p/8242592.html

      https://www.cnblogs.com/xiaoluo501395377/p/3383130.html