代理模式
介绍
代理模式(Proxy Pattern)是一种结构型设计模式,它提供了一个代理对象来控制对真实对象的访问。代理模式可以在不改变真实对象接口的情况下,为其添加额外的功能,如访问控制、延迟加载、日志记录等。
原理
代理模式的核心原理包括:
- 抽象主题:定义真实主题和代理主题的共同接口
- 真实主题:实现抽象主题,执行实际业务逻辑
- 代理主题:实现抽象主题,包含真实主题的引用,控制对真实主题的访问
图示
+----------------+ +----------------+
| Subject | | Client |
+----------------+ +----------------+
| + request() |<-------| + main() |
+-------^--------+ +----------------+
|
+-------+--------+ +----------------+
| RealSubject | | Proxy |
+----------------+ +----------------+
| + request() |<------| - realSubject |
+----------------+ | + request() |
+----------------+
代码示例
抽象主题
public interface Subject {
void request();
}
真实主题
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真实主题执行请求");
}
}
代理主题
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
// 前置处理
beforeRequest();
// 调用真实主题
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
// 后置处理
afterRequest();
}
private void beforeRequest() {
System.out.println("代理: 请求前处理");
}
private void afterRequest() {
System.out.println("代理: 请求后处理");
}
}
客户端代码
public class Client {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.request();
}
}
代理模式的类型
- 静态代理:编译时生成代理类
- 动态代理:运行时生成代理类
- JDK动态代理:基于接口
- CGLIB动态代理:基于继承
- 远程代理:控制对远程对象的访问
- 虚拟代理:延迟加载开销大的对象
- 保护代理:控制对对象的访问权限
- 缓存代理:为对象添加缓存功能
- 日志代理:记录对象的方法调用
动态代理示例(JDK)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("动态代理: 请求前处理");
Object result = method.invoke(realSubject, args);
System.out.println("动态代理: 请求后处理");
return result;
}
}
);
proxy.request();
}
}
解决方案
应用场景
- 访问控制:如权限验证
- 延迟加载:如虚拟代理
- 日志记录:记录方法调用信息
- 性能监控:统计方法执行时间
- 事务管理:为方法添加事务支持
- 缓存:缓存方法调用结果
- 远程调用:如RPC框架
最佳实践
- 接口隔离:代理类和真实类实现相同的接口
- 单一职责:每个代理类专注于一个功能
- 优先使用动态代理:减少代码量
- 结合工厂模式:创建代理对象
优缺点
优点:
- 保护真实对象
- 增强真实对象功能
- 控制访问权限
- 实现延迟加载
缺点:
- 增加代码复杂度
- 可能导致性能下降
- 调试难度增加
工具推荐
- Java JDK:提供动态代理API
- CGLIB:高性能的代码生成库,用于创建动态代理
- Spring Framework:提供AOP支持,基于代理模式
- AspectJ:强大的AOP框架
- MyBatis:使用代理模式实现Mapper接口