代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它允许你为其他对象提供一种代理以控制对这个对象的访问。代理模式在许多场景下都非常有用,例如延迟加载、访问控制、日志记录等。
代理模式的组成部分
代理模式主要由三个部分组成:
- 抽象主题(Subject):定义了真实主题和代理的共同接口,这样在任何使用真实主题的地方都可以使用代理。
- 真实主题(Real Subject):定义了代理所代表的具体对象。
- 代理(Proxy):持有对真实主题的引用,并负责在需要时创建或获取真实主题对象。代理可以控制对真实主题的访问,并可能在访问前后执行一些额外的操作。
代理模式的实现
代理模式可以通过多种方式实现,包括静态代理和动态代理。
静态代理
静态代理在编译时就已经确定代理类和真实主题类的关系。代理类通常是通过手动编写代码来实现的。
public interface Image {
void display();
}
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
// 从磁盘加载图片
}
@Override
public void display() {
// 显示图片
}
}
public class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
动态代理
动态代理是在运行时动态创建的代理类。在Java中,可以通过java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口来实现动态代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ImageInvocationHandler implements InvocationHandler {
private Object realImage;
public ImageInvocationHandler(Object realImage) {
this.realImage = realImage;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("display")) {
// 在调用真实主题的方法前后,可以执行一些额外的操作
}
return method.invoke(realImage, args);
}
}
public class ProxyFactory {
public static Object createProxy(Object realObject) {
return Proxy.newProxyInstance(
realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(),
new ImageInvocationHandler(realObject)
);
}
}
代理模式的应用场景
代理模式在以下场景中非常有用:
- 远程代理:为一个位于不同地址空间的对象提供一个本地代理对象,以便本地客户可以访问远程对象。
- 虚拟代理:用于创建开销较大的对象,通过代理来控制对其创建和访问,例如延迟加载。
- 保护代理:控制对原始对象的访问,用于保护对象不被不恰当的使用。
- 智能引用代理:在访问对象时执行一些额外的操作,例如计数引用、确保对象在使用前已被初始化等。
总结
代理模式是一种非常有用的设计模式,它通过引入一个代理对象来控制对真实对象的访问,从而可以在不修改真实对象的情况下增加额外的功能。代理模式在许多场景下都非常有用,包括但不限于延迟加载、访问控制、日志记录等。