在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
静态代理模式:
1.代理类与委托类(被代理类)有同样的接口
2.代理类主要负责为委托类(被代理类)预处理消息,过了消息,把消息转发给委托类,以及事后处理消息等。
3.一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务
静态代理
package ProxyPattern;
/*
1.抽象主题
2.定义了真实主题类(被委托类,被代理类)与代理类(委托类)的共同的业务接口
*/
public interface IPlayer {
void film();//拍电影的业务
}
package ProxyPattern;
public class Actor implements IPlayer{
private String name;
public Actor(String name) {
this.name = name;
}
@Override
public void film() {
System.out.println(name+"正在拍某某电影.....");
}
}
package ProxyPattern;
/*
1.代理类(委托类)
2.实现共同的业务接口,让我们的客户端能够通过这个代理类的业务接口间接的访问真实主题的业务
3.持有一个真实主题类的引用
*/
public class Manager implements IPlayer{
private String name;
private Actor actor;
public Manager(String name, Actor actor) {
this.name = name;
this.actor = actor;
}
@Override
public void film() {
System.out.println(name+"洽谈业务,约定拍电影的时间地点 价格。。。。");
//客户端间接访问真实业务
actor.film();
}
}
package ProxyPattern;
//代理模式的客户端
public class Client {
public static void main(String[] args) {
//静态代理
Actor qiangge = new Actor("强哥");
//构造一个代理类,并将真实对象传入
Manager mrSong = new Manager("宋先生", qiangge);
//访问真实业务
mrSong.film();
}
}
动态代理
动态代理没有具体的代理类
如Android的retrofit框架可以将许多的接口封装起来,然后一起调用
参考链接
package dynamicProxyPattern;
public class Zhangyuxin implements ZhangyuxinInterface{
@Override
public void sayHello() {
System.out.println("zhangyuxin在拍戏");
}
}
package dynamicProxyPattern;
public class Bingbing implements BingbingInterface{
@Override
public void sayBye() {
System.out.println("Bingbing在拍戏");
}
}
package dynamicProxyPattern;
public interface BingbingInterface {
void sayBye();
}
package dynamicProxyPattern;
public interface ZhangyuxinInterface {
void sayHello();
}
package dynamicProxyPattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
代理工厂
*/
public class DoSomeThingDynamic {
Object object;
public DoSomeThingDynamic(Object obj) {
this.object = obj;
}
/*
say需要代理执行的接口类
return 动态代理运行时生成的一个say对应类型的类的对象,用于调用say接口
*/
//Proxy.newProxyInstance运行时生成的过程,返回的时你传入的接口类型的对象,而这个对象就是代理
@SuppressWarnings("unchecked")
public <T> T create(final Class<T> say) {
//newProxyInstance方法的前两个参数对应的是下面object对象的两个类型
return (T) Proxy.newProxyInstance(say.getClassLoader(),
new Class<?>[]{say},
new InvocationHandler() {
/*
method 这个函数是反射的函数,method具体代表的是代理在执行的当前的函数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("拍戏前的准备工作");
//method是反射方法,对应的就是object对象的方法,而object对象是根据我们上面构造方法传的值进行赋值的
//在本例子中有也就是调用到的sayHello和sayBye
Object result = method.invoke(object,args);
System.out.println("拍戏后的首尾工作");
return result;
}
}
);
}
}
package dynamicProxyPattern;
public class Coder {
public static void main(String[] args) {
Zhangyuxin zyx=new Zhangyuxin();
//创建代理工厂
DoSomeThingDynamic say1=new DoSomeThingDynamic(zyx);
//当调用say1.create(ZhangyuxinInterface.class)时会生成一个字节码的类实现ZhangyuxinInterface
//所以我们可以用ZhangyuxinInterface来接收,相当于多态
//say1.create(ZhangyuxinInterface.class);创建了一个实现ZhangyuxinInterface接口的对象
//实现ZhangyuxinInterface接口的类不在我们的目录中是在运行的时候生成的所有看不到,需要转换成文件流才能看到。
ZhangyuxinInterface zhangyuxinProxy = say1.create(ZhangyuxinInterface.class);
//会调用实现ZhangyuxinInterface接口的对象中的sayHello方法
zhangyuxinProxy.sayHello();
Bingbing bb=new Bingbing();
DoSomeThingDynamic say2 = new DoSomeThingDynamic(bb);
BingbingInterface bbProxy = say2.create(BingbingInterface.class);
bbProxy.sayBye();
}
}
通过文件流生成一个字节码的类(类名可以自己设置)实现ZhangyuxinInterface,也就是实现ZhangyuxinInterface接口的类。
因为是代理类,不会自己去实现sayBye方法,而是通过方法this.h.invoke去实现
this.h就是 调用该方法对象的new InvocationHandler()函数(也就是调用本例子中的create方法的new InvocationHandler()),this.h.invoke就是调用该方法对象的new InvocationHandler()函数中的invoke方法。
简单的说:this.h就是你create的时候调用的newProxyInstance也就是创建动态代理对象中的InvocationHandler,后面this.h.invoke也就是调用我们InvocationHandler中的invoke方法
所以意味着我们调用实现接口类对象的方法都会调用到nvocationHandler()函数中的invoke方法
Android retrofit框架例子:
在retrofit中也用到动态代理,任何类型的接口都会需要走invoke,我们通过动态代理可以获取接口中所有@和参数值。然后通过对@和参数的解析拼装成一个URL,从而对网络进行请求。
这里的method是反射函数,具体指的是代理对象执行的函数也就是(代理对象api执行的getJson函数)。通过对method也就是getJson方法对应的注解和参数进行解析从而能够进行request网络请求