之前了解过,后来又忘了。我想这应该就是没有理解吧。所以,我整理下要点,加深印象。
首先,代理的意思:我们在下载网络资源的时候(特别是国外资源,比如Android SDK的包),因为网速较慢,所以会选择走代理,这样能快点。所以代理的意思,就像它的字面意思一样,A想访问B的时候,由于某些原因,需要通过C来进行访问,C在这个场景里就充当了代理了角色。当然,这里有必要对【适配器模式】和【装饰器模式】进行区分。1、适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口;2、装饰器模式为了增强功能,而代理模式是为了加以控制。
其次,代理模式(静态)的代码实现:在真实对象和代理之间抽出一个接口(真实对象和代理类都实现了该接口),代理类中包含了真实对象实例。这样当请求代理中的方法时(即接口中定义的那些方法),代理就可以调用真实对象的点该方法了(.display())
代码实例如下:
//1.接口文件定义
public interface Image {
void display();
}
//2.定义实体类文件
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);
}
}
//3.定义代理类的文件
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(); //毕竟只是代理,还是要调真正实体类的相应方法
//依然可以加些自己的处理
}
}
//4.使用代理模式的文件定义
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg"); //创建代理
// 图像将从磁盘加载
image.display(); //因为代理类中的实体对象,刚开始是空的,所以加调用构造函数
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
通过文件4的注释可以比较容易的分析出打印结果,如下:
Loading test_10mb.jpg
Displaying test_10mb.jpg
Displaying test_10mb.jpg
此时的代理模式实现似乎可以为我们提供点帮助。比如,我们想在display()之前之后做点什么。但随着实体类和代理类的增加,其代理模式就出现类的个数增加的问题,显然,需要了解下动态代理。而且这也是Java框架Spring的核心思想之一:IOC注解注入;AOP切面编程。
接着动态代理,JDK提供了两个类: java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。后者为接口,只包含一个函数:invoke(Object proxy, Method method, Object[] args)
第一个参数为:方法被调用的代理实例;第二个参数为:调用的方法;第三个参数为:调用方法的参数。
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
第一个参数:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。既然是代理对象,自然是实现了InvocationHandler这个接口的类;
第二个参数:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。既然是需要代理的对象,自然是真实对象所包含的方法了。真实对象才需要代理嘛。
第三个参数:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。显然是实现了InvocationHandler接口的类的对象。
紧接着上面的代码,我们编写动态代理的代码:
//3.动态代理的文件定义
public class DynamicProxy implements InvocationHandler{
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("proxy","before rent house");
Log.e("proxy","Method:" + method);
method.invoke(object,args);
Log.e("proxy","after rent house");
return null;
}
}
调用时的代码:
//4.调用文件的代码定义
public static void test() {
Image realImage = new RealImage("migu.cn");
InvocationHandler handler = new DynamicProxy(realImage);
Image proxyImage = (Image)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realImage.getClass().getInterfaces(),handler);
proxyImage.display();
proxyImage.hello("testmigusdk.network.proxy");
}
最后,参考文献:
http://www.runoob.com/design-pattern/proxy-pattern.html
https://www.cnblogs.com/xiaoluo501395377/p/3383130.html