代理模式(Proxy Pattern)是一种结构型设计模式,它允许你为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,客户端通过代理对象间接地访问目标对象。通过这种方式,代理模式可以在不修改目标对象的前提下,为目标对象添加额外的功能或控制访问权限。
本文将详细介绍代理模式的概念、种类、优缺点,并通过Java代码示例展示如何在实践中应用代理模式。
一、代理模式的概念
-
定义:代理模式为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,客户端通过代理对象间接地访问目标对象。
-
结构:
- Subject:抽象主题角色,声明了代理和真实对象的共同接口。
- RealSubject:真实主题角色,实现了抽象主题接口,是代理对象所代表的真实对象。
- Proxy:代理角色,持有一个真实对象的引用,可以控制对真实对象的访问,也可以附加额外的功能。
-
种类:
- 静态代理:代理类在编译时就确定下来,代理类和目标类的关系在运行前就已经确定,且不可改变。
- 动态代理:代理类在运行时由JVM根据反射机制动态生成,代理类和目标类的关系在运行时确定。
二、静态代理的理解和实践
静态代理通过定义一个代理类,并在代理类中调用目标对象的方法来实现。这种方式需要在编译时就确定代理类。
示例代码:
定义抽象主题接口:
// 抽象主题接口
public interface Image {void display();
}
实现真实主题类:
// 真实主题类
public class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk(filename);}private void loadFromDisk(String filename) {System.out.println("Loading " + filename);}@Overridepublic void display() {System.out.println("Displaying " + filename);}
}
定义代理类:
// 代理类
public class ProxyImage implements Image {private RealImage realImage;private String filename;public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();}
}
客户端代码:
public class Client {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");// 图像将从磁盘加载并显示image.display();}
}
在这个示例中,ProxyImage
是 RealImage
的代理类,它持有一个 RealImage
的引用,并在需要时才加载真实的图像对象。通过这种方式,可以在不修改 RealImage
的前提下,为其添加懒加载功能。
三、动态代理的理解和实践
动态代理通过Java反射机制在运行时动态生成代理类,而不需要在编译时确定代理类。Java提供了 java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口来实现动态代理。
示例代码:
定义抽象主题接口:
// 抽象主题接口
public interface Image {void display();
}
实现真实主题类:
// 真实主题类
public class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk(filename);}private void loadFromDisk(String filename) {System.out.println("Loading " + filename);}@Overridepublic void display() {System.out.println("Displaying " + filename);}
}
定义动态代理处理器:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;// 动态代理处理器
public class ImageInvocationHandler implements InvocationHandler {private Object realObject;public ImageInvocationHandler(Object realObject) {this.realObject = realObject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if ("display".equals(method.getName())) {System.out.println("Proxy: Loading image proxy...");Object result = method.invoke(realObject, args);return result;}return null;}
}
客户端代码:
import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {Image realImage = new RealImage("test.jpg");Image proxyInstance = (Image) Proxy.newProxyInstance(realImage.getClass().getClassLoader(),realImage.getClass().getInterfaces(),new ImageInvocationHandler(realImage));// 图像将通过代理加载并显示proxyInstance.display();}
}
在这个示例中,ImageInvocationHandler
是动态代理处理器,它实现了 InvocationHandler
接口。Proxy.newProxyInstance
方法在运行时动态生成代理类,并返回一个实现了 Image
接口的代理对象。客户端通过代理对象调用 display
方法时,会触发 ImageInvocationHandler
的 invoke
方法,从而实现对真实对象的访问控制。
四、代理模式的优缺点
优点:
- 增强功能:代理模式可以在不修改目标对象的前提下,为目标对象添加额外的功能。
- 控制访问:代理模式可以控制对目标对象的访问权限,例如限制访问次数或时间。
- 缓存和懒加载:代理模式可以实现缓存和懒加载机制,提高系统的性能和资源利用率。
缺点:
- 复杂性:代理模式增加了系统的复杂性,特别是当代理类较多时,代码会变得难以维护。
- 性能开销:代理模式在客户端和目标对象之间增加了一层中介,可能会引入额外的性能开销。
总结
代理模式是一种结构型设计模式,它允许你为其他对象提供一种代理以控制对这个对象的访问。代理模式可以在不修改目标对象的前提下,为目标对象添加额外的功能或控制访问权限。静态代理和动态代理是代理模式的两种实现方式,静态代理在编译时确定代理类,而动态代理在运行时动态生成代理类。通过Java代码示例,我们可以更好地理解和实践代理模式。