代理模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它為目標(biāo)對(duì)象提供一種代理,以控制對(duì)這個(gè)對(duì)象的訪問。代理對(duì)象在客戶端和目標(biāo)對(duì)象之間起到中介的作用,客戶端通過代理類與目標(biāo)對(duì)象進(jìn)行交互,而不是直接與目標(biāo)對(duì)象進(jìn)行交互。
代理模式的應(yīng)用場(chǎng)景非常廣泛,包括但不限于以下幾種情況:
- 訪問控制:當(dāng)客戶端不想或不能直接訪問某個(gè)對(duì)象時(shí),可以通過代理對(duì)象來間接訪問。例如,當(dāng)目標(biāo)對(duì)象是一個(gè)遠(yuǎn)程服務(wù)或者是一個(gè)復(fù)雜且耗時(shí)的操作時(shí),代理對(duì)象可以處理一些前置或后置的邏輯,如緩存、日志記錄或權(quán)限驗(yàn)證等。
- 功能增強(qiáng):代理模式可以在不修改目標(biāo)對(duì)象代碼的情況下,為目標(biāo)對(duì)象添加額外的功能。代理對(duì)象可以在調(diào)用目標(biāo)對(duì)象的方法前后添加新的邏輯,從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的增強(qiáng)。
- 安全控制:在某些情況下,直接訪問目標(biāo)對(duì)象可能存在安全風(fēng)險(xiǎn)。通過代理對(duì)象,可以對(duì)訪問進(jìn)行過濾或限制,確保只有滿足特定條件的客戶端才能訪問目標(biāo)對(duì)象。
代理模式主要分為靜態(tài)代理和動(dòng)態(tài)代理兩種類型:
- 靜態(tài)代理:在編譯時(shí)就已經(jīng)確定了代理類、接口和被代理類的關(guān)系。這種方式需要為每個(gè)被代理類手動(dòng)編寫代理類,因此當(dāng)被代理類較多時(shí),代碼量會(huì)比較大。
-
動(dòng)態(tài)代理:在運(yùn)行時(shí)通過反射機(jī)制動(dòng)態(tài)地創(chuàng)建代理類。這種方式不需要手動(dòng)編寫代理類,可以很方便地對(duì)代理類進(jìn)行統(tǒng)一處理。Java中的
java.lang.reflect.Proxy
類和CGLIB庫(kù)是實(shí)現(xiàn)動(dòng)態(tài)代理的常用工具。
代理模式的優(yōu)點(diǎn)包括:
- 分離目標(biāo)對(duì)象與客戶端:客戶端只與代理對(duì)象交互,降低了客戶端與目標(biāo)對(duì)象之間的耦合度。
- 增加靈活性:通過代理對(duì)象,可以靈活地控制對(duì)目標(biāo)對(duì)象的訪問,實(shí)現(xiàn)訪問控制、功能增強(qiáng)等目的。
- 易于擴(kuò)展:可以在不修改目標(biāo)對(duì)象代碼的情況下,為目標(biāo)對(duì)象添加新的功能或行為。
好的,下面我將使用Java代碼來描述代理模式中的靜態(tài)代理和動(dòng)態(tài)代理。
靜態(tài)代理
假設(shè)我們有一個(gè)接口Subject
和一個(gè)實(shí)現(xiàn)了該接口的類RealSubject
,以及一個(gè)代理類ProxySubject
。
// 接口定義
interface Subject {
void request();
}
// 真實(shí)對(duì)象
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("Called RealSubject.request()");
}
}
// 代理對(duì)象
class ProxySubject implements Subject {
private Subject realSubject;
public ProxySubject(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
// 在調(diào)用真實(shí)對(duì)象之前,可以添加一些預(yù)處理邏輯
System.out.println("Before calling RealSubject.request()");
realSubject.request();
// 在調(diào)用真實(shí)對(duì)象之后,可以添加一些后處理邏輯
System.out.println("After calling RealSubject.request()");
}
}
// 客戶端代碼
public class StaticProxyDemo {
public static void main(String[] args) {
// 創(chuàng)建真實(shí)對(duì)象
Subject realSubject = new RealSubject();
// 創(chuàng)建代理對(duì)象,并將真實(shí)對(duì)象傳遞給代理對(duì)象
Subject proxySubject = new ProxySubject(realSubject);
// 客戶端通過代理對(duì)象調(diào)用請(qǐng)求方法
proxySubject.request();
}
}
動(dòng)態(tài)代理
在Java中,動(dòng)態(tài)代理通常使用java.lang.reflect.Proxy
類實(shí)現(xiàn)。下面是一個(gè)動(dòng)態(tài)代理的示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口定義(與靜態(tài)代理中的相同)
interface Subject {
void request();
}
// 真實(shí)對(duì)象(與靜態(tài)代理中的相同)
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("Called RealSubject.request()");
}
}
// 調(diào)用處理器
class DynamicProxyHandler implements InvocationHandler {
private Object subject;
public DynamicProxyHandler(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在調(diào)用真實(shí)對(duì)象之前,可以添加一些預(yù)處理邏輯
System.out.println("Before calling method: " + method.getName());
Object result = method.invoke(subject, args);
// 在調(diào)用真實(shí)對(duì)象之后,可以添加一些后處理邏輯
System.out.println("After calling method: " + method.getName());
return result;
}
}
// 客戶端代碼
public class DynamicProxyDemo {
public static void main(String[] args) {
// 創(chuàng)建真實(shí)對(duì)象
Subject realSubject = new RealSubject();
// 創(chuàng)建調(diào)用處理器,并將真實(shí)對(duì)象傳遞給它
InvocationHandler handler = new DynamicProxyHandler(realSubject);
// 使用Proxy.newProxyInstance創(chuàng)建代理對(duì)象
Subject proxySubject = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class<?>[] { Subject.class },
handler);
// 客戶端通過代理對(duì)象調(diào)用請(qǐng)求方法
proxySubject.request();
}
}
在動(dòng)態(tài)代理中,Proxy.newProxyInstance
方法用于生成代理對(duì)象,它接受三個(gè)參數(shù):類加載器、代理類實(shí)現(xiàn)的接口數(shù)組以及調(diào)用處理器。調(diào)用處理器InvocationHandler
負(fù)責(zé)處理代理實(shí)例上的方法調(diào)用,并決定是否以及如何調(diào)用實(shí)際對(duì)象上的方法。
需要注意的是,動(dòng)態(tài)代理只能代理接口,如果要代理類,則需要使用如CGLIB這樣的第三方庫(kù)。文章來源:http://www.zghlxwxcb.cn/news/detail-854896.html
這些代碼示例展示了如何在Java中實(shí)現(xiàn)靜態(tài)代理和動(dòng)態(tài)代理。靜態(tài)代理需要手動(dòng)編寫代理類,而動(dòng)態(tài)代理則通過反射機(jī)制在運(yùn)行時(shí)動(dòng)態(tài)生成代理類,提供了更大的靈活性和可擴(kuò)展性。文章來源地址http://www.zghlxwxcb.cn/news/detail-854896.html
到了這里,關(guān)于設(shè)計(jì)模式之結(jié)構(gòu)型模式---代理模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!