在軟件開發(fā)中,經(jīng)常遇到需要對(duì)某個(gè)對(duì)象進(jìn)行控制或者監(jiān)控的場(chǎng)景。而直接修改對(duì)象的代碼可能使代碼變得復(fù)雜且難以維護(hù)。這時(shí),使用代理模式(Proxy Pattern)可以很好地解決這個(gè)問題。
?????????代理模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,通過引入一個(gè)代理對(duì)象來替代原始對(duì)象,實(shí)現(xiàn)對(duì)原有對(duì)象的控制或擴(kuò)展。Java中的代理模式常用于實(shí)現(xiàn)日志記錄、權(quán)限控制、事務(wù)控制等功能。
原理及實(shí)現(xiàn)思路
代理模式的核心思想是通過引入代理對(duì)象作為中間層,將客戶端的請(qǐng)求轉(zhuǎn)發(fā)給真正的對(duì)象,從而實(shí)現(xiàn)對(duì)真實(shí)對(duì)象的控制。
代理模式包含三個(gè)主要角色:
-
抽象主題(Subject):定義了代理對(duì)象和真實(shí)對(duì)象的共同接口。
-
真實(shí)主題(RealSubject):實(shí)現(xiàn)了抽象主題接口,是真正的業(yè)務(wù)邏輯處理對(duì)象。
-
代理主題(ProxySubject):實(shí)現(xiàn)了抽象主題接口,內(nèi)部持有一個(gè)真實(shí)主題對(duì)象的引用,通過代理對(duì)象間接調(diào)用真實(shí)對(duì)象。
實(shí)現(xiàn)代理模式的步驟如下:
-
創(chuàng)建抽象主題接口,定義需要代理的方法。
-
創(chuàng)建真實(shí)主題類,實(shí)現(xiàn)抽象主題接口,完成真正的業(yè)務(wù)邏輯。
-
創(chuàng)建代理主題類,實(shí)現(xiàn)抽象主題接口,持有一個(gè)真實(shí)主題對(duì)象的引用,在代理方法中調(diào)用真實(shí)主題的方法。
靜態(tài)代理
????????靜態(tài)代理是最簡(jiǎn)單的一種代理技術(shù),由程序員手動(dòng)編寫代理類來代替真實(shí)對(duì)象。靜態(tài)代理在編譯期生成代理類,在運(yùn)行時(shí)代理類不會(huì)發(fā)生變化。
????????靜態(tài)代理的優(yōu)點(diǎn)是簡(jiǎn)單易懂、易于實(shí)現(xiàn),但缺點(diǎn)也顯而易見,每個(gè)代理類只能代理一個(gè)具體類,當(dāng)代理類的數(shù)量較多時(shí),會(huì)導(dǎo)致代碼冗余,并且每個(gè)代理類只能代理一個(gè)固定的類。
示例代碼如下:
// 抽象主題接口
interface Subject {
void doSomething();
}
// 真實(shí)主題類
class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something.");
}
}
// 代理主題類
class ProxySubject implements Subject {
private Subject realSubject;
public ProxySubject(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doSomething() {
// 對(duì)真實(shí)主題方法的增強(qiáng)
System.out.println("Before do something.");
realSubject.doSomething();
System.out.println("After do something.");
}
}
// 客戶端代碼
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.doSomething();
}
}
動(dòng)態(tài)代理
????????動(dòng)態(tài)代理是在運(yùn)行時(shí)動(dòng)態(tài)地生成代理對(duì)象,相比于靜態(tài)代理,動(dòng)態(tài)代理更加靈活。Java中提供了兩種動(dòng)態(tài)代理的實(shí)現(xiàn)方式:基于接口的動(dòng)態(tài)代理和基于類的動(dòng)態(tài)代理。
????????基于接口的動(dòng)態(tài)代理使用java.lang.reflect.Proxy
類以及java.lang.reflect.InvocationHandler
接口來實(shí)現(xiàn)。
????????這種方式要求被代理類實(shí)現(xiàn)一個(gè)接口,并通過代理類來間接調(diào)用真實(shí)對(duì)象的方法。
示例代碼如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主題接口
interface Subject {
void doSomething();
}
// 真實(shí)主題類
class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something.");
}
}
// InvocationHandler實(shí)現(xiàn)類
class MyInvocationHandler implements InvocationHandler {
private Object realSubject;
public MyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 對(duì)真實(shí)主題方法的增強(qiáng)
System.out.println("Before do something.");
Object result = method.invoke(realSubject, args);
System.out.println("After do something.");
return result;
}
}
// 客戶端代碼
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new MyInvocationHandler(realSubject);
Subject proxySubject = (Subject) Proxy.newProxyInstance(
Client.class.getClassLoader(),
new Class[]{Subject.class},
handler);
proxySubject.doSomething();
}
}
基于類的動(dòng)態(tài)代理使用cglib
庫(kù),不要求被代理類實(shí)現(xiàn)接口,通過生成子類來實(shí)現(xiàn)代理。
示例代碼如下:
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
// 真實(shí)主題類
class RealSubject {
public void doSomething() {
System.out.println("RealSubject do something.");
}
}
// MethodInterceptor實(shí)現(xiàn)類
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 對(duì)真實(shí)主題方法的增強(qiáng)
System.out.println("Before do something.");
Object result = methodProxy.invokeSuper(object, args);
System.out.println("After do something.");
return result;
}
}
// 客戶端代碼
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new MyMethodInterceptor());
RealSubject proxySubject = (RealSubject) enhancer.create();
proxySubject.doSomething();
}
}
不同代理模式的優(yōu)缺點(diǎn)及適用場(chǎng)景
優(yōu)缺點(diǎn)
-
靜態(tài)代理的優(yōu)點(diǎn)在于簡(jiǎn)單易懂、易于實(shí)現(xiàn)。缺點(diǎn)是每個(gè)代理類只能代理一個(gè)具體類,導(dǎo)致代碼冗余,不夠靈活。
-
基于接口的動(dòng)態(tài)代理的優(yōu)點(diǎn)是可以代理實(shí)現(xiàn)了指定接口的任意對(duì)象,不需要修改原有代碼。缺點(diǎn)是只能代理接口中定義的方法。
-
基于類的動(dòng)態(tài)代理的優(yōu)點(diǎn)是可以代理任意類的對(duì)象,不需要修改原有代碼。缺點(diǎn)是不能代理
final
修飾的類和方法。
適用場(chǎng)景:
-
靜態(tài)代理適用于只需要代理少數(shù)幾個(gè)類,并且不需要頻繁地修改代理類的情況。
-
基于接口的動(dòng)態(tài)代理適用于需要對(duì)接口中的方法進(jìn)行控制和擴(kuò)展的情況。文章來源:http://www.zghlxwxcb.cn/news/detail-638077.html
-
基于類的動(dòng)態(tài)代理適用于不需要修改原有代碼、對(duì)類的任意方法進(jìn)行控制和擴(kuò)展的情況。文章來源地址http://www.zghlxwxcb.cn/news/detail-638077.html
到了這里,關(guān)于【設(shè)計(jì)模式】-代理模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!