代理
更新: 6/22/2025 字数: 0 字 时长: 0 分钟
定义
代理模式 (Proxy Pattern) 为其他对象提供一种代理以控制对这个对象的访问。代理模式通过引入代理对象间接访问目标对象,实现访问控制、功能增强、延迟加载等目的。
角色
- 抽象主题 (Subject):定义真实主题和代理的公共接口
- 真实主题 (Real Subject):实际业务执行对象
- 代理 (Proxy):控制对真实主题的访问,实现额外功能
- 客户端 (Client):通过代理访问真实主题
实现
虚拟代理(延迟加载)
java
// 抽象主题
public interface Image {
void display();
}
// 真实主题
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片:" + filename);
// 模拟耗时操作
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
@Override
public void display() {
System.out.println("显示图片:" + filename);
}
}
// 代理:控制访问并实现延迟加载
public class ProxyImage implements Image {
private String filename;
private RealImage realImage;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // 按需创建
}
realImage.display();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Image image = new ProxyImage("photo.jpg");
// 此时真实图片未加载
System.out.println("图片对象已创建");
// 第一次访问触发加载
image.display();
System.out.println("---");
// 第二次访问直接显示
image.display();
}
}
保护代理(访问控制)
java
// 抽象主题
public interface BankAccount {
void deposit(double amount);
void withdraw(double amount);
double getBalance();
}
// 真实主题
public class RealBankAccount implements BankAccount {
private double balance;
public RealBankAccount(double initialBalance) {
this.balance = initialBalance;
}
@Override
public void deposit(double amount) {
balance += amount;
}
@Override
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
} else {
throw new IllegalArgumentException("余额不足");
}
}
@Override
public double getBalance() {
return balance;
}
}
// 代理:添加访问控制
public class ProtectedBankAccount implements BankAccount {
private RealBankAccount realAccount;
private String owner;
private String currentUser;
public ProtectedBankAccount(String owner, double initialBalance) {
this.owner = owner;
this.realAccount = new RealBankAccount(initialBalance);
}
public void authenticate(String user) {
if (user.equals(owner)) {
currentUser = user;
} else {
throw new SecurityException("认证失败");
}
}
public void logout() {
currentUser = null;
}
private void checkAccess() {
if (currentUser == null) {
throw new SecurityException("请先登录");
}
}
@Override
public void deposit(double amount) {
checkAccess();
realAccount.deposit(amount);
}
@Override
public void withdraw(double amount) {
checkAccess();
realAccount.withdraw(amount);
}
@Override
public double getBalance() {
checkAccess();
return realAccount.getBalance();
}
}
// 使用示例
public class BankApp {
public static void main(String[] args) {
ProtectedBankAccount account = new ProtectedBankAccount("张三", 1000);
// 未认证访问
try {
account.getBalance(); // 抛出 SecurityException
} catch (SecurityException e) {
System.out.println("错误:" + e.getMessage());
}
// 认证后访问
account.authenticate("张三");
System.out.println("余额:" + account.getBalance());
account.deposit(500);
account.withdraw(200);
System.out.println("新余额:" + account.getBalance());
}
}
优缺点
优点:
- 控制对真实对象的访问
- 实现延迟加载,优化性能
- 增强目标对象功能(开闭原则)
- 降低系统耦合度
- 提高系统安全性和扩展性
缺点:
- 增加系统复杂度
- 可能降低响应速度(多层代理)
- 需要额外设计接口
- 可能引入额外开销
应用场景
- 远程代理(RPC、Web 服务)
- 虚拟代理(大资源延迟加载)
- 保护代理(访问控制)
- 智能引用(对象生命周期管理)
- 缓存代理(结果缓存)
- 防火墙代理(网络访问控制)
与其他模式的关系
- 与装饰器模式:都使用包装,但代理控制访问,装饰器增强功能
- 与适配器模式:适配器改变接口,代理保持接口
- 与外观模式:外观简化接口,代理控制访问
- 与桥接模式:桥接分离抽象与实现,代理控制访问
JDK 中的代理模式
- Java 动态代理(
java.lang.reflect.Proxy
) - RMI(远程方法调用)
- Spring AOP(面向切面编程)
- Hibernate 延迟加载(Lazy Initialization)
- Java 安全模型(SecurityManager)
注意事项
- 区分代理类型(虚拟/保护/远程等)
- 避免过度使用导致系统复杂化
- 考虑线程安全问题(共享代理状态)
- 注意代理链的性能影响
- 优先使用标准库代理机制(如 Java 动态代理)
- 为远程代理设计健壮的错误处理