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