系列文章
【設(shè)計(jì)模式】七大設(shè)計(jì)原則
【設(shè)計(jì)模式】第一章:單例模式
【設(shè)計(jì)模式】第二章:工廠模式
【設(shè)計(jì)模式】第三章:建造者模式
【設(shè)計(jì)模式】第四章:原型模式
【設(shè)計(jì)模式】第五章:適配器模式
【設(shè)計(jì)模式】第六章:裝飾器模式
【設(shè)計(jì)模式】第七章:代理模式
【設(shè)計(jì)模式】第八章:橋接模式
【設(shè)計(jì)模式】第九章:外觀模式 / 門面模式
【設(shè)計(jì)模式】第十章:組合模式
【設(shè)計(jì)模式】第十一章:享元模式
【設(shè)計(jì)模式】第十二章:觀察者模式
【設(shè)計(jì)模式】第十三章:模板方法模式
【設(shè)計(jì)模式】第十四章:策略模式
【設(shè)計(jì)模式】第十五章:責(zé)任鏈模式
【設(shè)計(jì)模式】第十六章:迭代器模式
【設(shè)計(jì)模式】第十七章:狀態(tài)模式
【設(shè)計(jì)模式】第十八章:備忘錄模式
【設(shè)計(jì)模式】第十九章:訪問者模式
【設(shè)計(jì)模式】第二十章:解釋器模式
【設(shè)計(jì)模式】第二十一章:命令模式
【設(shè)計(jì)模式】第二十二章:中介者模式
一、定義
摘自百度百科: 所謂的代理者是指一個類別可以作為其它東西的接口。代理者可以作任何東西的接口:網(wǎng)上連接、存儲器中的大對象、文件或其它昂貴或無法復(fù)制的資源。
二、角色分類
抽象主題角色(Subject)
定義了代理角色和真實(shí)主題角色的共同接口,代理角色通過該接口調(diào)用真實(shí)主題角色的方法。
真實(shí)主題角色(Real Subject)
實(shí)現(xiàn)了抽象主題角色的接口,代表真實(shí)的業(yè)務(wù)對象。
代理角色(Proxy)
實(shí)現(xiàn)了抽象主題角色定義的接口,并持有真實(shí)主題角色的引用,代表了真實(shí)主題角色的代理。在代理角色中,可以添加額外的功能,如記錄日志、權(quán)限控制等,而這些功能并不是真實(shí)主題角色本身所具備的功能
客戶(Client)
具體調(diào)用代理者的角色
三、UML圖
四、實(shí)現(xiàn)方式
需求分析
假如我們有一個這樣的場景:我們想要去看電影,但是我們嫌麻煩不想去電影院排隊(duì)買票,這時候我們可以選擇第三方的平臺來買票,并且代理會為我們處理一切的購票相關(guān)的事務(wù),包括選座、付款等。其實(shí)這種模式就相當(dāng)于我們設(shè)計(jì)模式中的代理模式,其代理第三方平臺,接下來我們用代碼來實(shí)現(xiàn)一下這個業(yè)務(wù)。
具體實(shí)現(xiàn)
簡單實(shí)現(xiàn)
抽象主題角色(Subject)
public interface Subject {
void request();
}
真實(shí)主題角色(Real Subject)
public class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject: 處理請求中");
}
}
代理角色(Proxy)
public class Proxy implements Subject {
private RealSubject realSubject;
public void request() {
if (null == realSubject) {
realSubject = new RealSubject();
}
preRequest();
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("Proxy: 請求前執(zhí)行邏輯");
}
private void postRequest() {
System.out.println("Proxy: 請求后執(zhí)行邏輯");
}
}
客戶角色(Client)
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy();
subject.request();
}
}
運(yùn)行結(jié)果
Proxy:請求前執(zhí)行邏輯
RealSubject: 處理請求中
Proxy: 請求后處理邏輯
動態(tài)代理
我們有一個接口 Subject 和其一個實(shí)現(xiàn)類 RealSubject,我們要使用JDK的動態(tài)代理來生成一個代理對象Proxy,代理對象的調(diào)用會轉(zhuǎn)發(fā)給RealSubject對象。
抽象主題角色(Subject)
public interface Subject {
void request();
}
真實(shí)主題角色(Real Subject)
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: 處理請求中");
}
}
動態(tài)代理角色(DynamicProxy)
public class DynamicProxy implements InvocationHandler {
private Object realObject;
public DynamicProxy(Object realObject) {
this.realObject = realObject;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 調(diào)用前執(zhí)行
System.out.println("DynamicProxy: 請求后執(zhí)行邏輯");
// 執(zhí)行實(shí)際方法
Object result = method.invoke(realObject, args);
// 調(diào)用后執(zhí)行
System.out.println("DynamicProxy: 請求后執(zhí)行邏輯");
return result;
}
}
客戶角色(Client)
public class Client {
public static void main(String[] args) {
// 創(chuàng)建被代理對象
RealSubject realSubject = new RealSubject();
// 創(chuàng)建代理對象
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader,
realSubject.getClass().getInterfaces(),
new DynamicProxy(realSubject)
);
// 調(diào)用代理對象的方法
proxy.request();
}
}
運(yùn)行結(jié)果
DynamicProxy: 請求前執(zhí)行邏輯
RealSubject: 處理請求中
DynamicProxy: 請求后執(zhí)行邏輯
在上述代碼中,RealSubject
表示真實(shí)的業(yè)務(wù)實(shí)現(xiàn)類,DynamicProxy
表示動態(tài)代理類,Client
表示客戶端。我們通過創(chuàng)建RealSubject
對象,然后創(chuàng)建一個代理對象proxy
來訪問RealSubject
。
在代理對象中,我們實(shí)現(xiàn)了InvocationHandler
接口,并重寫了其中的invoke()
方法,在調(diào)用代理對象的方法時,invoke()
方法會被自動調(diào)用。在invoke()
方法中,我們可以進(jìn)行一些額外的操作,比如在調(diào)用實(shí)際對象的方法前后添加日志等。
使用Proxy.newProxyInstance()
方法來創(chuàng)建代理對象。該方法需要傳入三個參數(shù):ClassLoader
對象,Class
對象數(shù)組和InvocationHandler
對象。其中,ClassLoader
對象用于加載代理類,Class
對象數(shù)組表示代理類需要實(shí)現(xiàn)的接口列表,InvocationHandler
對象用于處理代理對象的方法調(diào)用。
五、應(yīng)用場景
以下部分內(nèi)容摘自菜鳥教程
意圖: 為其他對象提供一種代理,以控制對這個對象的訪問。
主要解決: 解決了在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠(yuǎn)程的機(jī)器上。在面向?qū)ο笙到y(tǒng)中,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問),直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。
何時使用: 想在訪問一個類時做一些控制。
如何解決: 增加中間層。
關(guān)鍵代碼: 實(shí)現(xiàn)與被代理類組合。
應(yīng)用實(shí)例:
- Windows中的快捷方式
- 豬八戒去找高翠蘭,結(jié)果卻是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實(shí)現(xiàn)了這個接口,豬八戒在訪問高翠蘭的時候看不出來這個是悟空,所以此時孫悟空是高翠蘭的代理類
- 買火車票不一定在火車站買,也可以去代售點(diǎn)
- 一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來替代現(xiàn)金,并提供對簽發(fā)賬號上資金的控制
- Spring AOP
適用場景:
按職責(zé)劃分通常有以下場景:
- 遠(yuǎn)程代理
- 虛擬代理
- Copy-on-Write代理
- 保護(hù)(Protect or Access)代理
- Cache代理
- 防火墻(Firewall)代理
- 同步化(Synchronization)代理
- 智能引用(Smart Reference)代理
注意事項(xiàng):
- 和適配器模式區(qū)別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口
- 與裝飾器的區(qū)別:裝飾器模式為了增強(qiáng)功能,而代理模式是為了加以控制
六、優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 職責(zé)清晰
- 擴(kuò)展性高
- 智能化
缺點(diǎn)
- 由于在客戶端和真實(shí)主題中間加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢
- 實(shí)現(xiàn)代理模式需要額外的工作,有些代理模式的實(shí)現(xiàn)非常復(fù)雜
推薦
關(guān)注博客和公眾號獲取最新文章文章來源:http://www.zghlxwxcb.cn/news/detail-525415.html
Bummon’s Blog | Bummon’s Home | 公眾號文章來源地址http://www.zghlxwxcb.cn/news/detail-525415.html
到了這里,關(guān)于【設(shè)計(jì)模式】第七章:代理模式詳解及應(yīng)用案例的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!