代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对原始对象的访问。代理对象充当了客户端和目标对象之间的中介,可以在不改变目标对象的情况下增加额外的功能或限制访问。
在编译时就已经确定了被代理类和具体的代理类,在代码中直接定义一个具体的实现类作为目标对象和一个对应的具体实现类作为代理对象。静态代理需要手动编写每个方法的转发逻辑,并且只能针对特定类型进行操作。
- // 目标接口
- interface Image {
- void display();
- }
-
- // 目标类
- class RealImage implements Image {
- private String filename;
-
- public RealImage(String filename) {
- this.filename = filename;
- loadFromDisk();
- }
-
- private void loadFromDisk() {
- System.out.println("Loading image: " + filename);
- }
-
- @Override
- public void display() {
- System.out.println("Displaying image: " + filename);
- }
- }
-
- // 代理类
- class ImageProxy implements Image {
- private String filename;
- private RealImage realImage;
-
- public ImageProxy(String filename) {
- this.filename = filename;
- this.realImage = null; // 初始时不加载真实对象
- }
-
- @Override
- public void display() {
- if (realImage == null) { // 懒加载,只有在需要时才创建真实对象
- realImage = new RealImage(filename);
- }
- realImage.display();
- }
- }
-
- public class Main {
-
- public static void main(String[] args) {
-
- Image image1 = new ImageProxy("image1.jpg");//无输出
- // 使用代理显示图片,只有在调用 `display()` 方法时才会加载真实图片对象
- image1.display();//输出 Loading image: image1.jpg
- // Displaying image: image1.jpg
-
-
- Image image2 = new RealImage("image2.jpg");//输出Loading image: image2.jpg
- // 直接使用目标类显示图片,立即加载真实图片对象并显示
- image2.display();//输出 Displaying image: image2.jpg
- }
- }
在上述示例中,我们定义了一个目标接口 Image
和其具体实现类 RealImag
e
。然后创建了一个代理类 ImagProx
y来控制对目标对象的访问。当客户端创建代理类对象并不会马上加载图片,只有在调用display()时才会加载图片并展示图片。在创建目标对象时,会立刻加载图片。
动态代理是指在运行时动态生成代理类的过程,它不需要手动编写具体的代理类,而是通过 Java 的反射机制和字节码生成技术,在内存中创建一个新的代理类,并在运行时将方法调用转发给真实对象。
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-
- // 目标接口
- interface Image {
- void display();
- }
-
- // 目标类
- class RealImage implements Image {
- private String filename;
-
- public RealImage(String filename) {
- this.filename = filename;
- loadFromDisk();
- }
-
- private void loadFromDisk() {
- System.out.println("Loading image: " + filename);
- }
-
- @Override
- public void display() {
- System.out.println("Displaying image: " + filename);
- }
- }
-
- // InvocationHandler 实现类
- class ImageInvocationHandler implements InvocationHandler {
- private Object target;
-
- public ImageInvocationHandler(Object target) {
- this.target = target;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // 在方法调用前后可以执行一些额外操作,如权限验证、日志记录等
- System.out.println("Before method invocation");
- Object result = method.invoke(target, args);
- System.out.println("After method invocation");
- return result;
- }
- }
-
- public class Main {
-
- public static void main(String[] args) {
-
- RealImage realImage = new RealImage("image.jpg");
-
- // 创建代理对象并绑定目标对象和 InvocationHandler 对象
- Image proxyImage = (Image) Proxy.newProxyInstance(
- realImage.getClass().getClassLoader(),
- realImage.getClass().getInterfaces(),
- new ImageInvocationHandler(realImage)
- );
-
- // 通过代理对象调用方法,实际上会转发给真实对象的相应方法,并在前后执行额外操作
- proxyImage.display();
- }
- }
在上述示例中,我们定义了一个目标接口 Image 和其具体实现类 RealImage。然后创建了一个实现了 java.lang.reflect.InvocationHandler 接口的类 ImagInvocatioHandler来处理所有方法调用。最后使用 java.lang.reflect.Proxy 类的静态方法 newProxInstance() 来创建代理对象,并将目标对象和 InvocationHandler 对象绑定在一起。当客户端通过代理对象调用方法时,实际上会转发给真实对象的相应方法,并在前后执行额外操作。使用了 Java 的反射机制和字节码生成技术,在运行时动态地创建代理类。
存在问题: