1. 程式人生 > >Java 代理模式詳解

Java 代理模式詳解

代理模式是我們比較常用的設計模式之一。其中新思想是為了提供額外的處理或者不同的操作而在實際物件與呼叫者之間插入一個代理物件。這些額外的操作通常需要與實際物件進行通訊,代理模式一般涉及到的角色有: 

抽象角色:宣告真實物件和代理物件的共同介面; 

代理角色:代理物件角色內部含有對真實物件的引用,從而可以操作真實物件,同時代理物件提供與真實物件相同的介面以便在任何時刻都能代替真實物件。同時,代理物件可以在執行真實物件操作時,附加其他的操作,相當於對真實物件進行封裝。 

真實角色:代理角色所代表的真實物件,是我們最終要引用的物件。

以下以傳送訊息為例來說明一個簡單的代理模式的基本實現:

首先明確目的:有一條訊息,需要把這個訊息傳送出去,根據這個目的定義對應介面

MessageHandler。需要的附加操作:假設需要驗證訊息的長度不能超過指定長度並且不能為空,並且我們需要統計相關資訊傳送到次數,超過指定的次數我們需要輸出警報。我們通過代理模式來實現這個附加的操作。下面為對應的類關係圖及示例程式碼。

 

 在例子中我們可以方便的在訊息傳送過程中新增各種需要的附加處理方式,也能方便的替換訊息的處理方式,如將通過Email傳送訊息替換為通過簡訊傳送訊息,而呼叫方不會有絲毫察覺!在任何你想要將一些額外操作分離到具體物件之外,特別是希望能夠很容易做出修改,或者想在具體物件的方法執行前插入一些額外操作的時候,代理就顯得十分有用!

動態代理

java中動態代理機制的引入使得代理模式的思想更加完善與進步,它允許動態的建立代理並支援對動態的對所代理的方法進行呼叫。Java動態代理類位於Java.lang.reflect包下,一般主要涉及到以下兩個類: 

(1). Interface InvocationHandler

:該介面中僅定義了一個方法Objectinvoke(Object obj,Method method, Object[] args)。在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,如上例中的request()args為該方法的引數陣列。這個抽象方法在代理類中動態實現。 

(2).Proxy:該類即為動態代理類,作用類似於上例中的ProxySubject,其中主要包含以下內容: 

Protected Proxy(InvocationHandler h):建構函式,估計用於給內部的h賦值。 

Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部介面的陣列。 

Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當作被代理類使用(可使用被代理類的在Subject介面中宣告過的方法)。 

所謂Dynamic Proxy是這樣一種class:它是在執行時生成的class,在生成它時你必須提供一組interface給它,然後該class就宣稱它實現了這些interface。你當然可以把該class的例項當作這些interface中的任何一個來用。當然啦,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質性的工作,在生成它的例項時你必須提供一個handler,由它接管實際的工作。下面我們通過動態代理來重新實現上面傳送資訊的例子!

 

在上面的例子基礎上,我們先新增一個通過簡訊來發送訊息的處理類:

 以上例子中,通過呼叫Proxy.newProxyInstance方法建立動態代理物件,該方法需要傳入一個類載入器、一組希望代理實現的介面列表、InvocationHandler 介面的一個具體實現。動態代理可以將所有呼叫重定向到呼叫處理器,通常我們會向該處理器傳遞一個時間物件的引用。invoke()方法中傳遞進來了代理物件,當你需要區分請求來源時這是非常有用的,例如你可以通過判斷傳入的方法名遮蔽掉某些方法的執行!動態代理機制並不是會很頻繁使用的方法,它通常用來解決一些特定情況下的問題,因此不要盲目的為了使用而使用,要根據自己的實際需求來決定!