前言:Proxy是比較有用途的一種模式,而且變種較多,應(yīng)用場(chǎng)合覆蓋從小結(jié)構(gòu)到整個(gè)系統(tǒng)的大結(jié)構(gòu),Proxy是代理的意思,我們也許有代理服務(wù)器等概念,代理概念可以解釋為:在出發(fā)點(diǎn)到目的地之間有一道中間層,意為代理。
1.代理模式的定義
代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問方式;即通過代理對(duì)象訪問目標(biāo)對(duì)象。這樣做的好處是:可以在目標(biāo)對(duì)象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對(duì)象的功能。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式。

進(jìn)群:697699179可以獲取Java各類入門學(xué)習(xí)資料!
這是我的微信公眾號(hào)【編程study】各位大佬有空可以關(guān)注下,每天更新Java學(xué)習(xí)方法,感謝!
學(xué)習(xí)中遇到問題有不明白的地方,推薦加小編Java學(xué)習(xí)群:697699179內(nèi)有視頻教程 ,直播課程 ,等學(xué)習(xí)資料,期待你的加入
2.作用
中介隔離作用:
在某些情況下,一個(gè)客戶類不想或者不能直接引用一個(gè)委托對(duì)象,而代理類對(duì)象可以在客戶類和委托對(duì)象之間起到中介的作用,其特征是代理類和委托類實(shí)現(xiàn)相同的接口。
開閉原則,增加功能:
代理類除了是客戶類和委托類的中介之外,我們還可以通過給代理類增加額外的功能來擴(kuò)展委托類的功能,這樣做我們只需要修改代理類而不需要再修改委托類,符合代碼設(shè)計(jì)的開閉原則。代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后對(duì)返回結(jié)果的處理等。代理類本身并不真正實(shí)現(xiàn)服務(wù),而是同過調(diào)用委托類的相關(guān)方法,來提供特定的服務(wù)。真正的業(yè)務(wù)功能還是由委托類來實(shí)現(xiàn),但是可以在業(yè)務(wù)功能執(zhí)行的前后加入一些公共的服務(wù)。例如我們想給項(xiàng)目加入緩存、日志這些功能,我們就可以使用代理類來完成,而沒必要打開已經(jīng)封裝好的委托類。
3.優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1、職責(zé)清晰。
2、高擴(kuò)展性。
3、智能化。
缺點(diǎn):
1、由于在客戶端和真實(shí)主題之間增加了代理對(duì)象,因此有些類型的代理模式可能會(huì)造成請(qǐng)求的處理速度變慢。
2、實(shí)現(xiàn)代理模式需要額外的工作,有些代理模式的實(shí)現(xiàn)非常復(fù)雜。
4.代理模式的分類
如果按照代理創(chuàng)建的時(shí)期來進(jìn)行分類的話, 可以分為兩種:靜態(tài)代理、動(dòng)態(tài)代理。靜態(tài)代理是由程序員創(chuàng)建或特定工具自動(dòng)生成源代碼,在對(duì)其編譯。在程序員運(yùn)行之前,代理類.class文件就已經(jīng)被創(chuàng)建了;動(dòng)態(tài)代理是在程序運(yùn)行時(shí)通過反射機(jī)制動(dòng)態(tài)創(chuàng)建的。
5.代碼實(shí)現(xiàn)
5.1靜態(tài)代理
5.1.1 創(chuàng)建接口
packagestaticProxyPattern;// 創(chuàng)建法院接口publicinterfaceCourt{voiddoCourt();}
5.1.2 實(shí)現(xiàn)接口
packagestaticProxyPattern;publicclassPeopleimplementsCourt{//實(shí)現(xiàn)Court接口//在法庭上張三自己進(jìn)行辯解@OverridepublicvoiddoCourt(){System.out.println("張三說自己沒有偷東西");}}
5.1.3 對(duì)實(shí)現(xiàn)類添加功能
packagestaticProxyPattern;publicclassLawyerimplementsCourt{//接收需要代理的對(duì)象Courtzhangsan;publicLawyer(Courtzhangsan){this.zhangsan=zhangsan;}publicLawyer(){}//張三請(qǐng)律師進(jìn)行辯解@OverridepublicvoiddoCourt(){//張三自己先辯解zhangsan.doCourt();//律師替張三辯解System.out.println("經(jīng)視頻證明,并不是當(dāng)事人偷得東西");}}
5.1.4 測(cè)試
packagestaticProxyPattern;publicclassTest{publicstaticvoidmain(String[]args){//張三請(qǐng)律師打官司Peoplezhangsan=newPeople();Lawyerlawyer=newLawyer(zhangsan);lawyer.doCourt();}}
5.1.5 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):可以做到在符合開閉原則的情況下對(duì)目標(biāo)對(duì)象進(jìn)行功能擴(kuò)展。
缺點(diǎn):我們得為每一個(gè)服務(wù)都得創(chuàng)建代理類,工作量太大,不易管理;同時(shí)接口一旦發(fā)生改變,代理類也得相應(yīng)修改。
如何解決靜態(tài)代理的缺點(diǎn)呢? 這里就得說說動(dòng)態(tài)代理了。
在動(dòng)態(tài)代理中我們不再需要再手動(dòng)的創(chuàng)建代理類,我們只需要編寫一個(gè)動(dòng)態(tài)處理器就可以了。真正的代理對(duì)象由JDK再運(yùn)行時(shí)為我們動(dòng)態(tài)的來創(chuàng)建。
5.2 JDK中生成代理對(duì)象的API
代理類所在包:java.lang.reflect.Proxy;
JDK實(shí)現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個(gè)參數(shù),完整的寫法是:
staticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)
返回值:Object就是代理對(duì)象
ClassLoaderloader//代表與目標(biāo)對(duì)象相同的類加載器-------目標(biāo)對(duì)象.getClass().getClassLoader()Class<?>[]interfaces//代表與目標(biāo)對(duì)象實(shí)現(xiàn)的所有的接口字節(jié)碼對(duì)象數(shù)組----數(shù)組因?yàn)槟繕?biāo)類可以有多個(gè)接口InvocationHandlerh//事件處理,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)事件處理器的方法,//會(huì)把當(dāng)前執(zhí)行目標(biāo)對(duì)象的方法作為參數(shù)傳入。
5.3 動(dòng)態(tài)代理代碼實(shí)現(xiàn)
5.3.1 創(chuàng)建接口
packagestaticProxyPattern;// 創(chuàng)建法院接口publicinterfaceCourt{voiddoCourt();}
5.3.2 實(shí)現(xiàn)接口
packagestaticProxyPattern;publicclassPeopleimplementsCourt{//實(shí)現(xiàn)Court接口//在法庭上張三自己進(jìn)行辯解@OverridepublicvoiddoCourt(){System.out.println("張三說自己沒有偷東西");}}
5.3.3 代理律師
packagestaticProxyPattern;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassLawyer{publicObjectgetLawyer(Courtzhangsan){returnProxy.newProxyInstance(//對(duì)象的類加載器zhangsan.getClass().getClassLoader(),//該對(duì)象實(shí)現(xiàn)的所有的接口newClass[]{Court.class},//對(duì)該對(duì)象添加功能newInvocationHandler(){//proxy就是目標(biāo)對(duì)象,method就是調(diào)用目標(biāo)對(duì)象中方法,args就是調(diào)用目標(biāo)對(duì)象中方法的參數(shù)。//proxy的作用://1.可以使用反射獲取代理對(duì)象的信息(也就是proxy.getClass().getName())。//2.可以將代理對(duì)象返回以進(jìn)行連續(xù)調(diào)用,這就是proxy存在的目的,因?yàn)閠his并不是代理對(duì)象。@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//律師進(jìn)行申辯System.out.println("經(jīng)視頻證明,并不是當(dāng)事人偷得東西");//張三自己進(jìn)行申辯Objectinvoke=method.invoke(zhangsan,args);System.out.println("法院宣布,張三無罪釋放");returninvoke;}});}}
5.3.4 測(cè)試代碼
packagestaticProxyPattern;publicclassTest{publicstaticvoidmain(String[]args){//張三請(qǐng)律師打官司Peoplezhangsan=newPeople();Courtlawyer=(Court)newLawyer().getLawyer(zhangsan);lawyer.doCourt();}}
5.3.5 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
相對(duì)于靜態(tài)代理,動(dòng)態(tài)代理大大減少了我們的開發(fā)任務(wù),同時(shí)減少了對(duì)業(yè)務(wù)接口的依賴,降低了耦合度。
缺點(diǎn):
代理對(duì)象不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象一定要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理。