20210607# 代理设计模式

资源

简单示例

代理对象和真实对象可以实现同一个接口

public interface Image {
   void display();
}

真实对象(目标对象、被代理对象)实现该接口

public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}

代理对象(实现接口):持有真实对象的引用,可以调用真实对象的方法

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();
   }
}

客户端调用

  • 创建代理对象,赋值给定义的接口
  • 调用接口中定义的方法
    • 实际调用的是代理对象实现的方法
    • 内部会调用真实对象的方法
public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
      // 图像将从磁盘加载
      image.display(); 
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

JDK动态代理示例

定义一个接口,为其声明两个方法

public interface Subject
{
    public void rent();
    
    public void hello(String str);
}

接着,定义一个类来实现这个接口,这个类就是我们的真实对象,RealSubject类

public class RealSubject implements Subject {
    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str) {
        System.out.println("hello: " + str);
    }
}

下一步,我们就要定义一个动态代理类了,每一个动态代理类都必须要实现InvocationHandler这个接口

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {
    // 这个就是我们要代理的真实对象
    private Object subject;

    // 构造方法,给我们要代理的真实对象赋初值
    public DynamicProxy(Object subject) {
        this.subject = subject;
    }

    ////当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        // 在代理真实对象前我们可以添加一些自己的操作
        System.out.println("before rent house");

        System.out.println("Method:" + method);

        // 调用真实对象的方法
        method.invoke(subject, args);

        // 在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("after rent house");

        return null;
    }

}

最后,客户端调用

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        // 我们要代理的真实对象
        Subject realSubject = new RealSubject();

        // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        InvocationHandler handler = new DynamicProxy(realSubject);

        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数: handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数: realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实现的接口, 表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数: handler, 我们这里将这个代理对象关联到了上方的  InvocationHandler 这个对象上
         */
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);

        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
    }
}

控制台输出

com.sun.proxy.$Proxy0
before rent house
Method:public abstract void com.gaoth.Proxy.v2.Subject.rent()
I want to rent my house
after rent house
before rent house
Method:public abstract void com.gaoth.Proxy.v2.Subject.hello(java.lang.String)
hello: world
after rent house

posted @ 2021-06-07 09:48  傀儡岁月  阅读(32)  评论(0编辑  收藏  举报