【设计模式系列】代理模式(八)
一、什么是代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式在不直接访问实际对象的情况下,提供了对目标对象的间接访问。通过引入一个代理对象来间接操作实际对象,可以在不改变实际对象代码的前提下,增加额外的功能操作,如访问控制、延迟初始化、日志记录等。
二、代理模式的角色
-
主题(Subject):
- 提供了一个接口,使得代理对象和真实对象可以被同等对待。客户端通过这个接口与代理对象或真实对象交互,从而解耦了客户端和真实对象。
-
真实主题(Real Subject)
-
包含了业务逻辑的具体实现。它是最终执行操作的对象,但客户端不直接与它交互。
-
-
代理(Proxy):
-
在客户端和真实主题之间起到中介的作用。代理可以控制对真实主题的访问,可以在访问前后添加额外的处理,如访问控制、延迟初始化、日志记录等。
-
三、代理模式的典型应用
-
远程代理(Remote Proxy):在分布式系统中,远程代理用于隐藏对象位于不同地址空间的事实。客户端通过远程代理与远程对象进行交互,就好像它们在本地一样。典型案例是RPC框架
-
智能引用代理(Smart Reference Proxy):在访问对象时执行额外的操作,例如引用计数、加载持久对象到内存等。在资源管理中,智能引用代理可以用来跟踪对象的使用情况,并在适当的时候进行清理。
-
装饰代理(Decorator Proxy):在不修改对象的基础上,动态地添加额外的功能。这与装饰器模式相似,但通过代理模式实现,可以在运行时动态地添加或更换装饰。
四、代理模式在Proxy中的应用
在 Java 中,java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口是代理模式的典型应用。以下是它们在代理模式中的应用细节:
-
InvocationHandler 接口:这是 Java 提供的用于创建动态代理的核心接口。它定义了
invoke(Object proxy, Method method, Object[] args)
方法,该方法在代理实例上的方法被调用时将被调用。 -
Proxy 类:这个类提供了
newProxyInstance
方法,用于在运行时创建动态代理类实例。 -
真实主题(Real Subject):这是你想要代理的真实对象,它实现了特定的业务接口。
-
代理(Proxy):这是实现了与真实主题相同的接口的代理类,它的作用是在访问真实主题之前或之后进行额外的操作。
以下是一个简单的 Java 动态代理示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 真实主题接口
interface Subject {
void request();
}
// 真实主题实现
class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject: Handling request");
}
}
// 代理类
class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before the actual method call");
Object result = method.invoke(target, args);
System.out.println("After the actual method call");
return result;
}
}
// 客户端代码
public class ProxyPatternDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxyHandler proxyHandler = new ProxyHandler(realSubject);
Subject proxySubject = (Subject) proxyHandler.getProxyInstance();
proxySubject.request();
}
}
在这个示例中,RealSubject
是真实主题,实现了 Subject
接口。ProxyHandler
是代理类,实现了 InvocationHandler
接口,并在 invoke
方法中添加了额外的逻辑。客户端代码通过 ProxyHandler
创建了 RealSubject
的代理实例 proxySubject
,并通过代理实例调用了 request
方法。这样,ProxyHandler
就可以在调用真实主题的方法前后添加额外的操作,如日志记录。