標籤:method phi imp class 定義類 最大 gets ret 父類
原地址:http://blog.csdn.net/xu__cg/article/details/52970885
一、代理模式
為某個對象提供一個代理,從而控制這個代理的訪問。代理類和委託類具有共同的父類或父介面,這樣在任何使用委託類對象的地方都可以使用代理類對象替代。代理類負責請求的預先處理、過濾、將請求分配給委託類處理、以及委託類處理完請求的後續處理。
二、代理模式結構
UML類圖:
由代理模式的結構為:
- 抽象角色: 真實對象和代理對象的共同介面。
- 代理角色: 代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的介面以便在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當於對真實對象進行封裝。
- 真實角色: 代理角色所代表的真實對象,是我們最終要引用的對象。
根據代理類的產生時間不同可以將代理分為靜態代理和動態代理兩種。
三、靜態代理
由程式員建立或工具組建代理程式類的源碼,再編譯代理類。所謂靜態也就是在程式運行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在運行前就確定了。
範例程式碼:
1.抽象角色
public interface AbstractSubject { void doSomething();}
2.代理角色
public class ProxySubject implements AbstractSubject{ private AbstractSubject real ; public ProxySubject(AbstractSubject real) { this.real=real ; } @Override public void doSomething() { real.doSomething(); } public void doOtherthing() { }}
3.真實角色
public class RealSubject implements AbstractSubject{ @Override public void doSomething() { System.out.println( "真實角色被使用" ); }}
4.用戶端
public class Client { public static void main(String[] args ) { RealSubject real = new RealSubject(); ProxySubject proxy = new ProxySubject( real ); proxy.doSomething(); }}
5.靜態代理的優缺點
優點: 業務類只需要關注商務邏輯本身,保證了業務類的重用性。這是代理的共有優點。
缺點:
- 代理對象的一個介面只服務於一種類型的對象,如果要代理的方法很多,勢必要為每一種方法都進行代理,靜態代理在程式規模稍大時就無法勝任了。
- 如果介面增加一個方法,除了所有實作類別需要實現這個方法外,所有代理類也需要實現此方法。增加了代碼維護的複雜度。
四、動態代理
動態代理類的源碼是程式在運行期間由JVM根據反射等機制動態產生的,所以不存在代理類的位元組碼檔案。代理角色和真實角色的聯絡在程式運行時確定。
1.首先看看和動態代理相關JavaAPI
① .Java.lang.reflect.Proxy
這是Java動態代理機制產生的所有代理類的父類,它提供了一組靜態方法來為一組介面動態組建代理程式類及其對象。
Proxy類的靜態方法:
//方法 1: 該方法用於擷取指定代理對象所關聯的調用處理器 static InvocationHandler getInvocationHandler(Object proxy ) //方法 2:該方法用於擷取關聯於指定類裝載器和一組介面的動態代理類的類對象 static Class getProxyClass(ClassLoader loader,Class[] interfaces) //方法 3:該方法用於判斷指定類對象是否是一個動態代理類 static boolean isProxyClass(Class cl ) //方法 4:該方法用於為指定類裝載器、一組介面及調用處理器產生動態代理類執行個體static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h )
②.java.lang.reflect.InvocationHandler
這是調用處理器介面,它自訂了一個 invoke 方法,用於集中處理在動態代理類對象上的方法調用,通常在該方法中實現對委託類的代理訪問。每次產生動態代理類對象時都要指定一個對應的調用處理器對象。
InvocationHandler核心方法
//該方法負責集中處理動態代理類上的所有方法調用。第一個參數既是代理類執行個體,第二個參數是被調用的方法對象 //第三個方法是調用參數。調用處理器根據這三個參數進行預先處理或指派到委託類執行個體上反射執行 Object invoke(Object proxy, Method method,Object[] args )
③ .java.lang.reflect.ClassLoader
這是類裝載器類,負責將類的位元組碼裝載到 JAVA 虛擬機器(JVM)中並為其定義類對象,然後該類才能被使用。Proxy 靜態方法產生動態代理類同樣需要通過類裝載器來進行裝載才能使用,它與普通類的唯一區別就是其位元組碼是由 JVM 在運行時動態產生的而非預存在於任何一個 .class 檔案中。每次產生動態代理類對象時都需要指定一個類裝載器對象 。
2.動態代理實現步驟
- 實現InvocationHandler介面建立自己的調用處理器 。
- 給Proxy類提供ClassLoader和代理介面類型數組建立動態代理類 。
- 執行真實角色具體任務。
範例程式碼
1.抽象角色和真實角色代碼與上述相同 。
2. 建立自己的調用處理器:
public class SubjectHandler implements InvocationHandler{ AbstractSubject real; public SubjectHandler(AbstractSubject real){ this.real=real; } @Override public Object invoke(Object obj, Method method, Object[] args)throws Throwable { System.out.println("代理類預先處理任務"); //利用反射機制將請求指派給委託類處理。Method的invoke返回Object對象作為方法執行結果。 //因為樣本程式沒有傳回值,所以這裡忽略了傳回值處理 method.invoke(real, args); System.out.println("代理類後續處理任務"); return null; }}
3.用戶端 :
public class Client { public static void main(String[] args) { RealSubject real=new RealSubject(); SubjectHandler handler=new SubjectHandler(real); //組建代理程式類對象 AbstractSubject proxy=(AbstractSubject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{AbstractSubject.class},handler); proxy.doSomething(); }}
4.動態代理的優缺點
優點:
動態代理與靜態代理相比較,最大的好處是介面中聲明的所有方法都被轉移到調用處理器一個集中的方法中處理(InvocationHandler.invoke)。這樣,在介面方法數量比較多的時候,我們可以進行靈活處理,而不需要像靜態代理那樣每一個方法進行中轉。
不足:
誠然,Proxy 已經設計得非常優美,但是還是有一點點小小的遺憾之處,那就是它始終無法擺脫僅支援 interface 代理的桎梏,因為它的設計註定了這個遺憾。回想一下那些動態產生的代理類的繼承關係圖,它們已經註定有一個共同的父類叫 Proxy。Java 的繼承機制註定了這些動態代理類們無法實現對 class 的動態代理,原因是多繼承在 Java 中本質上就行不通。
本文動態代理部分內容大量引自:http://layznet.iteye.com/blog/1182924
Java設計模式學習06——靜態代理與動態代理(轉)