设计模式:代理模式
代理模式:為其他對象提供一種代理以控制對這個對象的訪問。代理模式中的角色:1. 抽象主題角色(Subject):聲明了目標對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。2. 具體主題角色(RealSubject):也稱為委托角色或者被代理角色。定義了代理對象所代表的目標對象。3. 代理主題角色(Proxy):也叫委托類、代理類。代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象。代理對象通常在客戶端調用傳遞給目標對象之前或之后,執行某個操作,而不是單純地將調用傳遞給目標對象。代理模式又分為靜態代理和動態代理。1. 靜態代理是由程序猿創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。2. 動態代理是在程序運行時,通過運用反射機制動態的創建而成。
##靜態代理1 Subjectpublic interface Subject {void operate();
}
2 RealSubjectpublic class RealSubject implements Subject {@Overridepublic void operate() {System.out.println("RealSubject");}}
3 Proxypublic class Proxy implements Subject {private Subject subject;@Overridepublic void operate() {if(subject==null) {subject = new RealSubject();System.out.println("I'm Proxy, I'm invoking...");this.subject.operate();}}}
4 測試代碼public class MainTest {public static void main(String[] args) {Subject subject = new Proxy();subject.operate();}}I'm Proxy, I'm invoking...
RealSubject
輸出:I’m Proxy, I’m invoking…RealSubject從上面例子可以看出代理對象將客戶端的調用為派給目標對象,在調用目標對象的方法之前和之后都可以執行特定的操作。
##動態代理動態代理是指在運行時,動態生成代理類。即,代理類的字節碼將在運行時生成并載入當前的ClassLoader。與靜態代理類想比,動態類有諸多好處。假如主題接口中的方法很多,為每一個接口寫一個代理方法也是非常煩人的事,如果接口有變動,則真實主題和代理類都要修改,不利于系統維護;其次,使用一些動態代理的生成方法甚至可以在運行時指定代理類的執行邏輯,從而大大提升系統的靈活性。
###Jdk動態代理Jdk的動態代理是基于接口的。現在想要為RealSubject這個類創建一個動態代理對象,Jdk主要會做一下工作:1. 獲取RealSubject上的所有接口列表2. 確定要生成的代理類的類名,默認為:com.sun.proxy.$ProxyXXXX;3. 根據需要實現的接口信息,在代碼中動態創建該Proxy類的字節碼;4. 根據需要實現的接口信息,在代碼中動態創建該Proxy類的字節碼;5. 創建InvocationHandler實例handler,用來處理Proxy所有方法的調用;6. Proxy的class對象以創建的handler對象為參數,實例化一個proxy對象;Jdk通過java.lang.reflect.Proxy包來支持動態代理,在Java中要創建一個代理對象,必須調用Proxy類的靜態方法newProxyInstance,該方法的原型如下:Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler handler) throws IllegalArgumentException1. loader,表示類加載器,對于不同來源(系統庫或網絡等)的類需要不同的類加載器來加載,這是Java安全模型的一部分。可以使用null來使用默認的加載器;2. interfaces,表示接口或對象的數組,它就是前述代理對象和真實對象都必須共有的父類或者接口;3. handler,表示調用處理器,它必須是實現了InvocationHandler接口的對象,其作用是定義代理對象中需要執行的具體操作。nvocationHandler之于Proxy,就如Runnable之于Thread。InvocationHandler接口中只有一個方法invoke,它的作用就跟Runnable中的run方法類似,定義了代理對象在執行真實對象的方法時所希望執行的動作。其原型如下:
proxy,表示執行這個方法的代理對象;method,表示真實對象實際需要執行的方法(關于Method類參見Java的反射機制);args,表示真實對象實際執行方法時所需的參數。
(修改代理類Proxy)import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyHandler implements InvocationHandler {Object obj = null;public Object newProxyInstance(Object realObj) {this.obj = realObj;Class<?> classType = this.obj.getClass();return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("I'm Proxy, I'm invoking...");method.invoke(obj, args);System.out.println("invoke end!");return null;}}
測試代碼:public class MainTest {public static void main(String[] args) {Subject subject = (Subject)new ProxyHandler().newProxyInstance(new RealSubject());subject.operate();}
}輸出結果:I'm Proxy, I'm invoking...
RealSubject
invoke end!
動態代理模式通過使用反射,可以在運行期決定加載哪個類,避免了一個類對應一個代理的問題;同時,通過統一的invoke方法,統一了代理類對原函數的處理過程,使用動態代理很大程度上減少了重復的代碼,降低了維護的復雜性和成本。
稍微修改一下代碼:1 Subjectpublic interface Subject {String operate1();String operate2();String operate3();String operate4();String operate5(); }
2 RealSubjectpublic class RealSubject1 implements Subject {@Overridepublic String operate1() {return "RealSubject1-operate1()";}@Overridepublic String operate2() {return "RealSubject1-operate2()";}@Overridepublic String operate3() {return "RealSubject1-operate3()";}@Overridepublic String operate4() {return "RealSubject1-operate4()";}@Overridepublic String operate5() {return "RealSubject1-operate5()";}}public class RealSubject2 implements Subject {@Overridepublic String operate1() {return "RealSubject2-operate1()";}@Overridepublic String operate2() {return "RealSubject2-operate2()";}@Overridepublic String operate3() {return "RealSubject2-operate3()";}@Overridepublic String operate4() {return "RealSubject2-operate4()";}@Overridepublic String operate5() {return "RealSubject2-operate5()";}}
3 Proxyimport java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyHandler implements InvocationHandler {Object obj = null;public Object newProxyInstance(Object realObj) {this.obj = realObj;Class<?> classType = this.obj.getClass();return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("I'm Proxy, I'm invoking...");Object object = method.invoke(obj, args);System.out.println(object);return null;}}
4 測試代碼public class MainTest {public static void main(String[] args) {Subject subject1 = (Subject) new ProxyHandler().newProxyInstance(new RealSubject1());Subject subject2 = (Subject) new ProxyHandler().newProxyInstance(new RealSubject2());subject1.operate2();subject2.operate4();}}
輸出:I'm Proxy, I'm invoking...
RealSubject1-operate2()
I'm Proxy, I'm invoking...
RealSubject2-operate4()
?
總結
- 上一篇: 设计模式:装饰模式(Decorator)
- 下一篇: 使用Github(仓库管理)