前言
在软件设计过程中,我们经常需要对对象或系统进行扩展。但是在开发过程中,直接修改现有代码可能会带来一些风险和不良影响,比如破坏原有的稳定性、影响已有的功能等。而代理模式则是通过引入一个代理对象来间接访问目标对象,从而为应用程序提供额外的功能和服务,且无需对目标对象进行任何修改。本篇文章将介绍Java中代理模式的定义、结构、实现方法以及应用场景,让您更好地理解代理模式的基本概念和应用。
1. 定义
代理模式是指「代理对象」与「被代理对象」实现相同的接口,代理对象通过持有或者引用被代理对象,在其提供的接口上实现了额外的操作,来起到对于被代理对象的辅助或者控制作用。在代理模式中,代理对象隐藏了真实对象的复杂度,并提供了一个类似或者增强了原有的接口。
一般而言,代理模式可以分为静态代理和动态代理两种。其中静态代理是在代码实现阶段就确定了代理类与目标类之间的关系,而动态代理是在运行时动态生成代理类。Java中,使用反射机制来实现动态代理。
2. 结构
代理模式通常包含以下几个角色:
- 抽象主题角色(Subject)
定义了目标对象和代理对象的公用接口,即抽象出了客户端需要调用的接口规范。
public interface Subject {
void doSomething();
}
- 真实主题角色(RealSubject)
定义了真正要处理的对象。
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("Do something in RealSubject.");
}
}
- 代理主题角色(ProxySubject)
通过持有或者引用了真实主题角色对象来实现抽象主题角色对象所定义的接口方法,并在其中实现额外的操作,比如对目标对象进行管理、监控等。
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doSomething() {
// 对目标对象进行辅助或控制
System.out.println("Do something before the real subject operation.");
realSubject.doSomething();
System.out.println("Do something after the real subject operation.");
}
}
在上述代码中,真实主题角色是RealSubject,它实现了Subject接口;代理主题角色是ProxySubject,它也实现了Subject接口,并在其实现中引用了真实主题对象realSubject,并在其中实现了额外的操作。
3. 实现方法
代理模式的实现方法分为静态代理和动态代理两种:
3.1 静态代理
在静态代理中,代理类与目标类的关系在代码实现阶段就已经确定。我们需要手动写出代理类,同时代理类与目标类继承同一接口或抽象类。代理类负责包装原始对象实现。以下是静态代理的实现示例:
public interface ISubject {
void request();
}
public class RealSubject implements ISubject {
@Override
public void request() {
System.out.println("Real Subject Request.");
}
}
public class ProxySubject implements ISubject {
private final ISubject realSubject;
public ProxySubject(ISubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("Proxy Subject Request.");
realSubject.request();
System.out.println("End Proxy Subject Request.");
}
}
public static void main(String[] args) {
// 创建真实主题对象
RealSubject realSubject = new RealSubject();
// 创建代理主题对象,传入真实主题对象
ProxySubject proxySubject = new ProxySubject(realSubject);
// 调用代理主题对象的方法
proxySubject.request();
}
3.2 动态代理
动态代理是在运行时利用Java反射机制动态生成代理类,无需手动编写代理类。当需要代理的对象实现了指定接口时,我们可以使用Java提供的Proxy和InvocationHandler来创建动态代理。
public interface ISubject {
void request();
}
public class RealSubject implements ISubject {
@Override
public void request() {
System.out.println("Real Subject Request.");
}
}
public class DynamicProxy implements InvocationHandler {
private final Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Dynamic Proxy Request.");
// 调用被代理对象的方法
Object result = method.invoke(target, args);
System.out.println("End Dynamic Proxy Request.");
// 返回被代理对象的方法返回值
return result;
}
}
public static void main(String[] args) {
// 创建真实主题对象
RealSubject realSubject = new RealSubject();
// 创建动态代理对象,传入真实主题对象
ISubject proxySubject = (ISubject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
new Class[]{ISubject.class},
new DynamicProxy(realSubject));
// 调用代理主题对象的方法
proxySubject.request();
}
在上述代码中,我们使用了Java中的Proxy类和InvocationHandler接口来实现动态代理。我们首先定义一个接口ISubject和一个实现该接口的RealSubject对象,然后创建一个实现了InvocationHandler接口的DynamicProxy对象,并在其中实现了代理的额外操作。最后使用Java提供的Proxy.newProxyInstance方法生成动态代理对象。
4. 应用场景
代理模式通常应用于以下场景:
- 远程代理:远程代理是指直接访问远程对象的方法,通过代理类来隐藏网络通信和复杂的处理细节,让客户端感知不到远程调用的过程。
- 虚拟代理:虚拟代理是指用一个较简单的对象来代表一个复杂的对象,可以使系统资源利用率更高,也可延迟真正需要执行的操作,提高系统的效率。
- 安全代理:安全代理用来控制真实对象的访问权限,保护目标对象不被非法访问或篡改。
- 智能代理:智能代理是指在访问对象时,进行额外的处理,如增加引用计数,记录访问日志,缓存结果等。