在 Java 编程中,代理模式是一种结构型设计模式,它允许通过代理对象来控制对目标对象的访问。代理模式为其他对象提供了一种代理以控制对这个对象的访问。以下是 Java 代理模式的一些常见应用场景:
远程代理(Remote Proxy)
远程代理是为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台机器中,也可是在另一台机器中。远程代理主要用于远程方法调用(Remote Method Invocation,RMI),它使得客户端可以像调用本地对象一样调用远程对象的方法,而不需要了解远程对象的具体实现细节。
例如,在分布式系统中,客户端需要调用远程服务器上的业务逻辑。如果直接调用远程服务器的方法,会涉及到网络通信、序列化和反序列化等复杂的操作,增加了开发的难度和性能开销。使用远程代理后,客户端可以通过本地的代理对象来调用远程服务器的方法,代理对象负责处理与远程服务器的通信和数据交互,客户端只需要关注业务逻辑的调用,提高了开发效率和系统的可维护性。
以下是一个简单的远程代理示例代码:
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// 定义远程接口
interface RemoteService extends Remote {
String remoteMethod() throws RemoteException;
}
// 实现远程接口的远程对象
class RemoteServiceImpl extends UnicastRemoteObject implements RemoteService {
protected RemoteServiceImpl() throws RemoteException {
super();
}
@Override
public String remoteMethod() throws RemoteException {
return "This is a remote method call.";
}
}
// 远程代理类
class RemoteProxy implements RemoteService {
private RemoteService remoteService;
public RemoteProxy() throws RemoteException {
remoteService = new RemoteServiceImpl();
}
@Override
public String remoteMethod() throws RemoteException {
return remoteService.remoteMethod();
}
}
在上述代码中,RemoteService
是远程接口,RemoteServiceImpl
是实现了远程接口的远程对象,RemoteProxy
是远程代理类。客户端通过调用代理对象的remoteMethod
方法,实际上是调用了远程对象的remoteMethod
方法,实现了远程方法调用。
虚拟代理(Virtual Proxy)
虚拟代理是根据需要创建开销很大的对象。通过使用虚拟代理,在对象创建之前可以进行一些初始化操作,或者在对象创建后延迟加载对象的某些部分,以提高系统的性能。
例如,加载一张大图片时,如果立即加载整个图片,可能会导致程序启动缓慢或者内存占用过高。使用虚拟代理后,可以先加载一张小缩略图,当用户需要查看大图时,再加载完整的图片。这样可以在需要时才创建真正的对象,避免了不必要的资源消耗。
以下是一个简单的虚拟代理示例代码:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
// 真实对象:图片加载器
class ImageLoader {
private String imagePath;
private BufferedImage image;
public ImageLoader(String imagePath) {
this.imagePath = imagePath;
}
public BufferedImage loadImage() {
try {
image = ImageIO.read(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
}
// 虚拟代理:代理图片加载器
class ImageProxy {
private String imagePath;
private ImageLoader imageLoader;
private BufferedImage image;
public ImageProxy(String imagePath) {
this.imagePath = imagePath;
}
public BufferedImage getImage() {
if (image == null) {
imageLoader = new ImageLoader(imagePath);
image = imageLoader.loadImage();
}
return image;
}
}
在上述代码中,ImageLoader
是真实对象,负责加载图片。ImageProxy
是虚拟代理,在需要获取图片时才创建ImageLoader
对象并加载图片。这样可以在需要时才进行图片加载,提高了程序的性能。
保护代理(Protection Proxy)
保护代理用于控制对对象的访问权限。它可以根据用户的角色或权限来决定是否允许访问对象的方法或属性。保护代理通常用于访问控制、权限管理等场景。
例如,在一个企业级应用中,不同的用户具有不同的权限,有些用户可以访问某些敏感数据,而有些用户则不能。使用保护代理后,可以在访问敏感数据之前进行权限检查,只有具有相应权限的用户才能访问。
以下是一个简单的保护代理示例代码:
class Subject {
public void request() {
System.out.println("Accessing protected resource.");
}
}
class ProtectionProxy implements Subject {
private Subject subject;
private String user;
private String password;
public ProtectionProxy(Subject subject, String user, String password) {
this.subject = subject;
this.user = user;
this.password = password;
}
@Override
public void request() {
if (authenticate()) {
subject.request();
} else {
System.out.println("Access denied.");
}
}
private boolean authenticate() {
// 模拟身份验证逻辑
return "admin".equals(user) && "123456".equals(password);
}
}
在上述代码中,Subject
是被保护的对象,ProtectionProxy
是保护代理。在调用subject
的request
方法之前,先进行身份验证,如果验证通过则调用subject
的request
方法,否则拒绝访问。
缓存代理(Cache Proxy)
缓存代理用于缓存对象的计算结果或数据,以提高系统的性能。当第一次请求某个对象时,缓存代理会计算并缓存该对象的结果。下次请求相同的对象时,缓存代理直接返回缓存的结果,而不需要重新计算。
例如,在计算密集型的应用中,某个方法的计算结果可能需要花费很长时间。使用缓存代理后,可以将计算结果缓存起来,下次调用时直接从缓存中获取,避免了重复计算,提高了系统的性能。
以下是一个简单的缓存代理示例代码:
import java.util.HashMap;
import java.util.Map;
// 被代理的对象
class Calculation {
public int performCalculation(int num) {
// 模拟复杂的计算过程
int result = num * num;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}
// 缓存代理
class CacheProxy {
private Calculation calculation;
private Map<Integer, Integer> cache = new HashMap<>();
public CacheProxy(Calculation calculation) {
this.calculation = calculation;
}
public int performCalculation(int num) {
if (cache.containsKey(num)) {
return cache.get(num);
}
int result = calculation.performCalculation(num);
cache.put(num, result);
return result;
}
}
在上述代码中,Calculation
是被代理的对象,CacheProxy
是缓存代理。在调用calculation
的performCalculation
方法之前,先检查缓存中是否已经存在该计算结果,如果存在则直接返回缓存的结果,否则进行计算并将结果缓存起来。
总之,Java 代理模式在远程调用、延迟加载、访问控制和缓存等方面都有广泛的应用。通过使用代理模式,可以提高系统的性能、可维护性和安全性。在实际开发中,根据具体的需求选择合适的代理模式,可以更好地设计和实现系统。