JAVA設計模式之----------代理模式(Proxy)__JAVA

來源:互聯網
上載者:User

這裡只是簡單的介紹下最基本的代理的使用。


代理,通俗點說 :就是一個人或者一個機構代表另一個人或者另一個機構採取行動。

在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在客戶

端和目標對象之前起到中介的作用。
代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象的引用。


UML圖

從上面的圖我們能看到代理涉及的角色:

 抽象對象角色:聲明了目標對象和代理對象的共同介面,

這樣一來在任何可以使用目標對象的地方都可以使用代理對象。

  目標對象角色:定義了代理對象所代表的目標對象。(也就是要代理的是誰)

            代理對象角色:代理對象內部含有目標對象的引用,從而可以在任何時候

操作目標對象;代理對象提供一個與目標對象相同的介面,以便可以在任何時候替代目標對象。

代理對象通常在用戶端調用傳遞給目標對象之前或之後,執行某個操作,而不是單純地將調用

傳遞給目標對象。    


我們在這裡示範一個房東,中介和客戶之間的關係(中介就是代理)

1,我們需要一個抽象的對象角色:(介面)

public interface IRenter {public abstract void rent();}

2,我們需要的目標對象:(就是實現的介面的類)

public class Renter implements IRenter{@Overridepublic void rent() {System.out.println("我是房東,開始收費咯咯");}}


3,代理對象的角色(就是我們的代理)

我們需要用到這個Java中代理使用的類

Object o =Proxy.newProxyInstance(loader, interfaces, h)

public class Client {@Testpublic void Test2(){ final Renter r =new Renter();//被代理的對象//o是中介代理之後的對象Object o =Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{IRenter.class},new InvocationHandler() <span style="white-space:pre"></span>{@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
//從這裡開始就是開始攔截要控制的內容了,如if(method.getName.equals('rent')){將方法名為rent的函數,做出你想要的事情}//System.out.println("aaaa");//這裡只是簡單的每個方法之前輸出System.out.println("收點費用");return method.invoke(r, args); //<span style="font-family: 'ms shell dlg';">return method.invoke(要代理的對象, 參數傳進來什麼參數就放出什麼參數,這裡相當於全部放開);}} );IRenter ir =(IRenter) o;//最後在使用的時候需要  將對象  強轉為介面類型的ir.rent();}}

通過上面的簡單介紹,能發現,一個代理類的所有方法或函數,都要經過代理之後,才會進行操作,指定操作的方法做我們想做的事情,沒有指定的直接允許存取

上面的只是一個簡單的介紹例子,下面介紹一個在實際中的使用例子。

我們在串連資料庫的時候,都是採用的連結池的方式,但是連結池裡面的串連都是有限個的,

所以我們需要每個用完之後就將其放回池中,但是單獨去寫一個函數將其放回池中,不太好用,

所以,我們就將 con.close()關閉串連的時候,不去關,而是直接的放回池中,

讓其他的線程來調用,也就是需要攔截con裡面的close方法。

所需要的三個角色:

1,介面對象  connection介面

2,實現對象   Connectioncon=DriverManager.getConnection(url, user, password);//在進行串連的時候可以。

3,需要我們的代理類。

下面這是整個串連池的代碼:

public class hibernateFactory2 {private static final int NUM=3;private static List<Connection> pool =new ArrayList<Connection>();static{//讀取設定檔Properties p =new Properties();try {p.load(hibernateFactory.class.getClassLoader().getResourceAsStream("jdbc.properties"));//讀取裡面的值,一直修改設定檔即可String driver=p.getProperty("driver");String url=p.getProperty("url");String user=p.getProperty("username");String password=p.getProperty("password");System.out.println(driver+url+user+password);Class.forName(driver);for(int i=0;i<NUM;i++){final Connectioncon=DriverManager.getConnection(url, user, password);//採用動態代理開始進行對connection介面實現代理,對con.close,實現換回去</span><span style="color:#ff0000;">Object o =Proxy.newProxyInstance(hibernateFactory2.class.getClassLoader(), new Class[]{Connection.class},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {if(method.getName().equals("close")){ //攔截close方法pool.add((Connection)(proxy));//將串連還回池System.out.println("換回來了。。。");return null;}return method.invoke(con, args);//其餘的全部允許存取}});pool.add((Connection)o);}//System.out.println("初始化完畢"+con);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//下面是擷取串連。public static synchronized Connection getCon() throws Exception{if(pool.size()<=0){System.out.println("pool中已經沒有串連");return getCon() ;}System.out.println("使用一個。。");return  pool.remove(0); //兩種方法都是可以的//while(pool.size()<=0){//System.out.println("池中已經乜有串連");//Thread.sleep(1000);//}//return pool.remove(0);//}}}

在上面的基礎上,我們寫了一個通用的版本

public class proxyUtils {public static Object getProxy(final Object srcobj){Object o = Proxy.newProxyInstance(proxyUtils.class.getClassLoader(),srcobj.getClass().getInterfaces(), //這句可以修改new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("被攔擊了。。。。");//這裡採用攔截return  method.invoke(srcobj, args);//傳回值我們也可以進行一些列的操作}});return o;}}
但是我們在調用的這個工具的時候,必須傳進來一個執行個體對象,也就是實現了的類

如 IA 為介面 A 為實作類別

A a =new A();

IA ia =(IA)proxyUtils.getProxy(a);

通過ia 的對象調用方法就可以。


上面方法的另一種實現形式

public class proxyUtils2 implements InvocationHandler{private Object srcobj;public proxyUtils2(Object srcobj) {this.srcobj=srcobj;}public static Object getProxy(final Object srcobj){Object o = Proxy.newProxyInstance(proxyUtils2.class.getClassLoader(),srcobj.getClass().getInterfaces(), //這句可以修改 ,在不知道的情況下,這種方法最好 new proxyUtils2(srcobj));return o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("在這裡採用攔截");Object obj =method.invoke(srcobj, args);//在這裡我們還可以進行對返回的值進行操作,這也是代理帶來的好處return obj;}}

上面的這些都是採用代理設計模式實現的,其實 代理模式就相當於一個秘書,能幫你做你想做的事情。


代理應用方面(從別人哪裡看到的)

 代理模式的應用形式

(1)遠程代理(Remote Proxy) -可以隱藏一個對象存在於不同地址空間的事實。也使得用戶端可以訪問在遠程機器上的對象,遠程機器可能具有更好的計算效能與處理速度,可以快速響應並處理用戶端請求。

(2)虛擬代理(Virtual Proxy) – 允許記憶體開銷較大的對象在需要的時候建立。只有我們真正需要這個對象的時候才建立。

(3)寫入時複製代理(Copy-On-Write Proxy) – 用來控制對象的複製,方法是延遲物件的複製,直到客戶真的需要為止。是虛擬代理的一個變體。

(4)保護代理(Protection (Access)Proxy) – 為不同的客戶提供不同層級的目標對象存取權限

(5)緩衝代理(Cache Proxy) – 為開銷大的運算結果提供暫時儲存,它允許多個客戶共用結果,以減少計算或網路延遲。

(6)防火牆代理(Firewall Proxy) – 控制網路資源的訪問,保護主題免於惡意客戶的侵害。

(7)同步代理(SynchronizationProxy) – 在多線程的情況下為主題提供安全的訪問。

(8)智能引用代理(Smart ReferenceProxy) - 當一個對象被引用時,提供一些額外的操作,比如將對此對象調用的次數記錄下來等。

(9)複雜隱藏代理(Complexity HidingProxy) – 用來隱藏一個類的複雜集合的複雜度,並進行存取控制。有時候也稱為外觀代理(Façade Proxy),這不難理解。複雜隱藏代理和面板模式是不一樣的,因為代理控制訪問,而面板模式是不一樣的,因為代理控制訪問,而面板模式只提供另一組介面。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.