Java 中的代理模式:使用智能代理增强安全性和控制
大约 3 分钟
也称为
- 代理
代理设计模式的意图
Java 中的代理模式提供了一个代理或占位符,可以有效地控制对对象的访问,从而增强安全性并管理资源。
代理模式的详细解释及真实世界示例
真实世界示例
在真实世界的场景中,考虑一个封闭社区的保安。保安充当居民的代理。当访客到达时,保安会检查访客的凭证和权限,然后再允许他们进入社区。如果访客被授权,保安会授予进入权限;如果不是,则拒绝进入。这确保只有授权人员才能访问社区,就像代理设计模式控制对特定对象的访问一样。
通俗地说
利用 Java 代理模式,一个类封装了另一个类的功能,简化了访问控制和操作效率。
维基百科说
代理,在其最一般的形式中,是一个充当其他事物的接口的类。代理是一个包装器或代理对象,它被客户端调用以访问幕后的实际服务对象。代理的使用可以简单地转发到实际对象,也可以提供额外的逻辑。在代理中,可以提供额外的功能,例如,当对实际对象的运算资源密集时进行缓存,或者在调用实际对象的运算之前检查先决条件。
Java 中代理模式的编程示例
想象一座塔,当地的巫师在那里学习他们的咒语。这座象牙塔只能通过一个代理进入,该代理确保只有前三个巫师可以进入。这里代理代表了塔的功能,并为其添加了访问控制。
首先,我们有WizardTower
接口和IvoryTower
类。
public interface WizardTower {
void enter(Wizard wizard);
}
@Slf4j
public class IvoryTower implements WizardTower {
public void enter(Wizard wizard) {
LOGGER.info("{} enters the tower.", wizard);
}
}
然后是一个简单的Wizard
类。
public class Wizard {
private final String name;
public Wizard(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
然后我们有WizardTowerProxy
来为WizardTower
添加访问控制。
@Slf4j
public class WizardTowerProxy implements WizardTower {
private static final int NUM_WIZARDS_ALLOWED = 3;
private int numWizards;
private final WizardTower tower;
public WizardTowerProxy(WizardTower tower) {
this.tower = tower;
}
@Override
public void enter(Wizard wizard) {
if (numWizards < NUM_WIZARDS_ALLOWED) {
tower.enter(wizard);
numWizards++;
} else {
LOGGER.info("{} is not allowed to enter!", wizard);
}
}
}
这是进入塔楼的场景。
public static void main(String[] args) {
var proxy = new WizardTowerProxy(new IvoryTower());
proxy.enter(new Wizard("Red wizard"));
proxy.enter(new Wizard("White wizard"));
proxy.enter(new Wizard("Black wizard"));
proxy.enter(new Wizard("Green wizard"));
proxy.enter(new Wizard("Brown wizard"));
}
程序输出
08:42:06.183 [main] INFO com.iluwatar.proxy.IvoryTower -- Red wizard enters the tower.
08:42:06.186 [main] INFO com.iluwatar.proxy.IvoryTower -- White wizard enters the tower.
08:42:06.186 [main] INFO com.iluwatar.proxy.IvoryTower -- Black wizard enters the tower.
08:42:06.186 [main] INFO com.iluwatar.proxy.WizardTowerProxy -- Green wizard is not allowed to enter!
08:42:06.186 [main] INFO com.iluwatar.proxy.WizardTowerProxy -- Brown wizard is not allowed to enter!
何时在 Java 中使用代理模式
每当需要对对象的更通用或更复杂的引用(而不是简单的指针)时,代理都是适用的。以下是代理模式适用的几种常见情况。通常,代理模式用于
- 控制对另一个对象的访问
- 延迟初始化
- 实现日志记录
- 促进网络连接
- 计算对对象的引用次数
- 为位于不同地址空间中的对象提供本地表示。
Java 中代理模式的真实世界应用
- 虚拟代理:在需要大量资源(如大型图像或复杂计算)的应用程序中,虚拟代理可用于仅在需要时实例化对象。
- 远程代理:用于远程方法调用 (RMI) 中以管理与远程对象的交互。
- 保护代理:控制对原始对象的访问以确保适当的授权。
- java.lang.reflect.Proxy
- Apache Commons Proxy
- 模拟框架 Mockito、Powermock、EasyMock
- UIAppearance
代理模式的优点和权衡
优点
- 受控访问:代理控制对实际对象的访问,允许进行检查、日志记录或其他操作。
- 延迟初始化:代理可以延迟资源密集型对象的创建和初始化,直到需要时才进行。
- 远程代理处理:通过处理网络通信来简化与远程对象的交互。
权衡
- 开销:添加代理会引入额外的层,这可能会增加开销。
- 复杂性:通过添加更多类来增加系统的复杂性。
相关的 Java 设计模式
- 适配器:适配器模式改变现有对象的接口,而代理提供与原始对象相同的接口。
- 大使:大使类似于代理,因为它充当中间人,尤其是在远程通信中,增强了访问控制和监控。
- 装饰器:装饰器模式和代理模式都提供了一定程度的间接性,但装饰器模式动态地为对象添加职责,而代理模式则控制访问。
- 外观:外观为复杂的子系统提供了一个简化的接口,而代理则控制对特定对象的访问。