目錄
1、什么是代理模式
2、代理模式的結(jié)構(gòu)
3、代理模式的實(shí)現(xiàn)
3.1 靜態(tài)代理和動(dòng)態(tài)代理概念
3.2?靜態(tài)代理
3.3 動(dòng)態(tài)搭理
3.3.1 代碼實(shí)現(xiàn)
3.3.2 Proxy類講解
4、動(dòng)態(tài)代理VS靜態(tài)代理
5、代理模式優(yōu)缺點(diǎn)
1、什么是代理模式
由于某些原因需要給某對象提供一個(gè)代理以控制對該對象的訪問。這時(shí),訪問對象不適合或者不能直接引用目標(biāo)對象,代理對象作為訪問對象和目標(biāo)對象之間的中介。
2、代理模式的結(jié)構(gòu)
代理(Proxy)模式分為三種角色:
- 抽象主題(Subject)類: 通過接口或抽象類聲明真實(shí)主題和代理對象實(shí)現(xiàn)的業(yè)務(wù)方法。
- 真實(shí)主題(Real Subject)類: 實(shí)現(xiàn)了抽象主題中的具體業(yè)務(wù),是代理對象所代表的真實(shí)對象,是最終要引用的對象。
- 代理(Proxy)類 : 提供了與真實(shí)主題相同的接口,其內(nèi)部含有對真實(shí)主題的引用,它可以訪問、控制或擴(kuò)展真實(shí)主題的功能。
3、代理模式的實(shí)現(xiàn)
3.1 靜態(tài)代理和動(dòng)態(tài)代理概念
Java中的代理按照代理類生成時(shí)機(jī)不同又分為靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理代理類在編譯期就生成,而動(dòng)態(tài)代理代理類則是在Java運(yùn)行時(shí)動(dòng)態(tài)生成。動(dòng)態(tài)代理又有JDK代理和CGLib代理兩種。
(本文中的動(dòng)態(tài)代理主要講解的是JDK代理,如果大家對CGLib代理感興趣的話可以自行查閱網(wǎng)上的文章)?
3.2?靜態(tài)代理
我們直接通過案例來感受一下動(dòng)態(tài)代理,以下是場景描述:
一般明星(對象本身)都會(huì)有一個(gè)經(jīng)紀(jì)人(代理對象)來幫他處理一些事情,比如明星開演唱會(huì)之前收門票費(fèi)用,預(yù)約場地,演唱會(huì)結(jié)束之后調(diào)查觀眾對該演唱會(huì)的反饋之類的事情肯定不能交給大明星做吧,所以這些事情一般都是交給經(jīng)紀(jì)人去處理。
這個(gè)例子就是一個(gè)典型的代理例子,因此我們來看看通過靜態(tài)代理如何實(shí)現(xiàn):
明星類(抽象主題類):
public interface bigStar {//抽象主題類
String Sing();
void Dance();
}
坤坤類(真實(shí)主題類):
public class KunKun implements bigStar{ //真實(shí)主題類
public String Sing(){
System.out.println("大明星:坤坤開始唱歌");
return "雞你太美"; //返回歌詞
}
public void Dance(){
System.out.println("大明星:坤坤開始跳舞");
}
}
?經(jīng)紀(jì)人類(代理類):
public class StaticProxy implements bigStar{ //代理類
private bigStar star;
public StaticProxy(bigStar bigStar){
star=bigStar;
}
@Override
public String Sing() {
System.out.println("唱歌前收取門票費(fèi)用、預(yù)約場地");
String sing = star.Sing();
System.out.println("唱歌結(jié)束后幫忙調(diào)查觀眾反饋");
return sing;
}
@Override
public void Dance() {
System.out.println("跳舞前收取門票費(fèi)用、預(yù)約場地");
star.Dance();
System.out.println("跳舞結(jié)束后幫忙調(diào)查觀眾反饋");
}
}
測試類:
public class Test {
public static void main(String[] args) {
KunKun kunKun = new KunKun();
StaticProxy proxy = new StaticProxy(kunKun);
proxy.Dance();
System.out.println("------");
String sing = proxy.Sing();
System.out.println("歌詞為:"+sing);
}
}
運(yùn)行結(jié)果如下:
可見,我們通過“靜態(tài)代理”的方式實(shí)現(xiàn)了“代理模式”,成功在“坤坤”唱歌、跳舞前做好了準(zhǔn)備工作以及在結(jié)束后做好了調(diào)查觀眾反饋的工作。這些都是代理類來完成的,看到這里大家肯定意識(shí)到了代理模式的一個(gè)好處就是:“在被代理對象方法執(zhí)行前后能做一定的處理、加強(qiáng)”。
但是上述靜態(tài)代理模式有沒有缺點(diǎn)呢?
有!而且很明顯!那就是:“雜!亂!如果接口增加一個(gè)方法,靜態(tài)代理模式除了所有實(shí)現(xiàn)類需要實(shí)現(xiàn)這個(gè)方法外,所有代理類也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。”
因此,我們引出另一種實(shí)現(xiàn)代理模式的方法:“動(dòng)態(tài)代理”。
3.3 動(dòng)態(tài)搭理
3.3.1 代碼實(shí)現(xiàn)
動(dòng)態(tài)代理的JDK代理實(shí)現(xiàn)主要是通過“Proxy類”來實(shí)現(xiàn)的,我們直接來看代碼實(shí)現(xiàn),大家耐心看,代碼里面有很詳細(xì)的注釋??床欢梢韵瓤吹紫聦τ诶锩鎱?shù)的講解部分。
大明星類(抽象主題類):
public interface bigStar { //大明星類(抽象主題類)
public String Sing();
public void Dance();
}
坤坤類(真實(shí)主題類):
public class KUN implements bigStar { //坤坤類(真實(shí)主題類)
@Override
public String Sing() {
System.out.println("坤坤在唱歌......");
//返回歌詞
return "雞你太美";
}
@Override
public void Dance() {
System.out.println("坤坤在跳舞");
}
}
經(jīng)紀(jì)人(代理類):
public class StarProxyFactory { //經(jīng)紀(jì)人(代理類)
public static bigStar getProxy(bigStar star){
bigStar result=(bigStar)Proxy.newProxyInstance( //newProxyInstance()方法即返回代理對象
// newProxyInstance()方法參數(shù)說明:
// ClassLoader loader : 類加載器,用于加載代理類,使用真實(shí)對象的類加載器即可
// Class<?>[] interfaces : 真實(shí)對象所實(shí)現(xiàn)的接口,代理模式真實(shí)對象和代理對象實(shí)現(xiàn)相同的接口
// InvocationHandler h : 代理對象的調(diào)用處理程序
star.getClass().getClassLoader(),
star.getClass().getInterfaces(),
new InvocationHandler() {
@Override
// InvocationHandler中invoke方法參數(shù)說明:
// proxy:代理對象
// method:對應(yīng)于在代理對象上調(diào)用的接口方法的 Method 實(shí)例,比如我們調(diào)用了“Sing()”這個(gè)方法,那么對應(yīng)的就是“Sing()”的Method實(shí)例
// args:對應(yīng)我們方法傳入的參數(shù)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("場地布置、收取門票費(fèi)用");
Object invoke = method.invoke(star, args);
System.out.println("場地打掃");
return invoke; //返回方法調(diào)用結(jié)果
}
}
);
return result;
}
}
測試類:
public class Test {
public static void main(String[] args) {
KUN kun = new KUN();
bigStar proxy = StarProxyFactory.getProxy(kun);//獲取動(dòng)態(tài)代理對象
//驗(yàn)證是否被代理
proxy.Dance();
System.out.println("--------------");
String sing = proxy.Sing();
System.out.println("歌詞為:"+sing);
}
}
運(yùn)行結(jié)果如下:
可見,我們通過Java提供的“Proxy類”也實(shí)現(xiàn)了代理的效果,但是大家看完可能會(huì)一臉懵逼,發(fā)生了什么?我在哪?我是誰?
因此接下來我們對“Proxy類”這個(gè)類做一個(gè)詳細(xì)的解釋。
3.3.2 Proxy類講解
首先,我們剛剛是通過Proxy.newProxyInstance()來獲取一個(gè)代理對象,它所需要的參數(shù)如下:
可見,我們?nèi)绻褂?strong>Proxy.newProxyInstance()的話,需要對它傳入以下參數(shù):
①參數(shù)一:指類加載器,意思是需要我們告訴它我們需要用哪個(gè)類加載器去加載代理對象,通常我們代理對象與被代理對象可以使用同一個(gè)類加載器,因此比如上文我們是代理star對象,因此我們傳入的類加載器就是:“star.getClass().getClassLoader()”。
②參數(shù)二:指真實(shí)對象所實(shí)現(xiàn)的接口,代理模式真實(shí)對象和代理對象實(shí)現(xiàn)相同的接口,因此我們也直接傳入真實(shí)對象的接口即可:“star.getClass().getInterfaces()”。
③參數(shù)三:指代理對象最終調(diào)用的程序,一般代理對象調(diào)用某個(gè)方法后,都會(huì)走我們參數(shù)三寫的這個(gè)方法,大家往回看代碼會(huì)發(fā)現(xiàn)我們參數(shù)三傳入了一個(gè)匿名內(nèi)部類對象“new InvocationHandler()”
大家又可以發(fā)現(xiàn),這個(gè)“InvocationHandler類”創(chuàng)建對象時(shí),要求重寫里面的invoke方法:
?我們再來逐一說說這幾個(gè)參數(shù)的作用:
- proxy:代理對象本身
- method:對應(yīng)于在代理對象上調(diào)用的接口方法的 Method 實(shí)例,比如我們調(diào)用了“Sing()”這個(gè)方法,那么對應(yīng)的就是“Sing()”的Method實(shí)例
- args:對應(yīng)我們方法傳入的參數(shù)
因此呢,我們可以在invoke方法里面做一些方法加強(qiáng)(比如我們之前的代碼),也就是我們的“代理”。
以上便是動(dòng)態(tài)代理實(shí)現(xiàn)代理模式的代碼。
4、動(dòng)態(tài)代理VS靜態(tài)代理
動(dòng)態(tài)代理與靜態(tài)代理相比較,最大的好處是接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個(gè)集中的方法中處理(InvocationHandler.invoke)。這樣,在接口方法數(shù)量比較多的時(shí)候,我們可以進(jìn)行靈活處理,而不需要像靜態(tài)代理那樣每一個(gè)方法進(jìn)行中轉(zhuǎn)。
如果接口增加一個(gè)方法,靜態(tài)代理模式除了所有實(shí)現(xiàn)類需要實(shí)現(xiàn)這個(gè)方法外,所有代理類也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。而動(dòng)態(tài)代理不會(huì)出現(xiàn)該問題
5、代理模式優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- ?代理模式在客戶端與目標(biāo)對象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對象的作用。
- 代理對象可以擴(kuò)展目標(biāo)對象的功能。
- 代理模式能將客戶端與目標(biāo)對象分離,在一定程度上降低了系統(tǒng)的耦合度。
缺點(diǎn):文章來源:http://www.zghlxwxcb.cn/news/detail-435566.html
- 增加了系統(tǒng)的復(fù)雜度。
以上是代理模式的詳解,大家麻煩點(diǎn)個(gè)贊和關(guān)注可以嘛!現(xiàn)在點(diǎn)關(guān)注就是老粉啦!文章來源地址http://www.zghlxwxcb.cn/news/detail-435566.html
到了這里,關(guān)于設(shè)計(jì)模式之代理模式(靜態(tài)代理&動(dòng)態(tài)代理)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!