1. 程式人生 > >JAVA設計模式-動態代理(Proxy)示例及說明

JAVA設計模式-動態代理(Proxy)示例及說明

一,概念

  代理設計模式的目的就是在不直接操作物件的前提下對物件進行訪問,實現這個目的得方法就是為目標物件建立一個代理(Proxy),通過代理來訪問目標物件。這個設計模式的優點是什麼呢?程式碼重用,符合開閉原則。

  這樣解釋可能會不太好理解,那麼接下來就通俗的來說一下代理:

  1,不知道你知不知道VPN(也就是俗稱的科學上網),在黨的領導下,為了營造我國健康的的網路環境國外的一些網站在我國是無法訪問的。例如:google。但是因為某些行業的特殊性需要訪問這些國內不可訪問的網站,那麼怎麼辦呢?這個時候就需要代理(正向代理)了,怎麼實現呢?例如:香港可以訪問國內不可訪問的網站,而國內卻可以訪問香港的網站。那麼就可以這樣做“國內->香港伺服器(代理)->國外網站”。這裡就用到了代理。

  2,更通俗的例子就是,作者小的時候被狗狗追著跑,所以到現在作者看到狗狗,特別是體型龐大的狗狗的時候,就會害怕。假如一個狗狗有一天突然搶了作者的包子,那怎麼辦呢?那隻能委託狗狗的主人,讓狗狗把包子還給作者(r如果狗狗還沒吃掉)。這裡的主人也是扮演了代理的角色。

  3,再來一個,作者是王力巨集的歌迷。也一直很想點歌給王力巨集唱。要怎麼辦?直接找他,估計沒時間搭理我,最有希望的就是找他的經紀人,通過經紀人,傳達我想點的歌。這個時候這個經紀人就是代理。

二,動態代理程式碼示例

  那麼接下來就以上面說到第三個例子,用程式碼展示一下代理模式。代理模式分為靜態代理和動態代理,本文只說明動態代理。

  1,王力巨集是一個歌手,我們首先建立一個Singer介面類,並宣告一個點歌和告別的方法

 1 package com.zcz.proxyTest.testtwo;
 2 
 3 public interface Singer {
 4     /**
 5      * 根據歌名點歌
 6      * @param songName
 7      */
 8     public void orderSong(String songName);
 9     /**
10      * 向觀眾告別
11      * @param audienceName
12      */
13     public void sayGoodBye(String audienceName);
14 }

  2,接下來實現王力巨集類,並實現介面中的兩個方法。

package com.zcz.proxyTest.testtwo;

public class WangLiHong implements Singer {

    @Override
    public void orderSong(String songName) {
        // TODO Auto-generated method stub
        System.out.println("演唱歌曲:"+songName);
    }

    @Override
    public void sayGoodBye(String audienceName) {
        // TODO Auto-generated method stub
        System.out.println("再見:"+audienceName);
    }

}

   3,就算我找到了經紀人(代理),那我也不能隨便就叫經紀人通知(呼叫)王力巨集(目標物件)唱歌(的方法),我還要準備一個感人肺腑的故事,但是我又不會講故事,這個時候,經紀人就提供給了我一個模板(呼叫處理類,一個介面),讓我按照模板編寫故事(實現invoke方法)

package com.zcz.proxyTest.testtwo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyStoryInvocationHandler implements InvocationHandler {
    private Object object;
    
    public MyStoryInvocationHandler(Object o) {
        // TODO Auto-generated constructor stub
        this.object = o;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("力巨集,我是你代理經紀人:"+proxy.getClass().getName());
        //處理業務
        System.out.println("巴拉巴拉......(講了一個故事)");
        
        for(Object arg:args) {
            System.out.println("傳入的引數:"+arg);
        }
        
        //通知力巨集做事情
        method.invoke(object, args);
        
        //處理業務
        System.out.println("巴拉巴拉,感謝........");
        
        return null;
    }

}

  4,OK,到這裡所有的準備工作就完成了,接下來就開始吧。

package com.zcz.proxyTest.testtwo;

import java.lang.reflect.Proxy;

public class MyPorxy {
    public static void main(String[] args) {
        //例項化目標物件(創造一個力巨集)
        WangLiHong liHong = new WangLiHong();
        //例項化呼叫處理類(編好的故事)
        MyStoryInvocationHandler handler = new MyStoryInvocationHandler(liHong);
        
        //接下來建立代理(經紀人)
        
        //準備一個類載入器
        ClassLoader loader =   MyPorxy.class.getClassLoader();
        //獲取目標物件的介面類物件陣列
        Class<?>[] interfaces = liHong.getClass().getInterfaces();
        
        //建立代理
        Singer proxy = (Singer) Proxy.newProxyInstance(loader, interfaces, handler);
        
        //開始點歌
        proxy.orderSong("就是現在");
        System.out.println("****** 歌唱中......********");
        //歌唱完了,say goodBye吧
        proxy.sayGoodBye("zhangchengzi");
        
    }
}

  5,好,現在右鍵-> Run As -> Java Application。看列印結果:

力巨集,我是你代理經紀人:com.sun.proxy.$Proxy0
巴拉巴拉......(講了一個故事)
傳入的引數:就是現在
演唱歌曲:就是現在
巴拉巴拉,感謝........
****** 歌唱中......********
力巨集,我是你代理經紀人:com.sun.proxy.$Proxy0
巴拉巴拉......(講了一個故事)
傳入的引數:zhangchengzi
再見:zhangchengzi
巴拉巴拉,感謝........

  6,看到了嗎?我們不沒有直接使用目標物件的方法,而是構造出一個代理物件,通過代理來訪問了目標物件的方法。總結一下,想要實現動態代理需要四個關鍵元素

    1,一個介面A

    2,一個繼承介面A,並實現A中抽象方法的實現類

    3,一個實現了InvocationHandler的呼叫處理類

    4,呼叫Proxy.newProxyInstance方法,獲取代理類

更多幹貨,請查閱目錄