1.代理模式定义
为其他对象提供一种代理控制这个对象的访问。说白了就是我们生活中的经纪人,我们想要做什么事情,都需要先询问经纪人,经纪人在来询问我们。
2.使用场景
当无法或不想直接访问某个对象或者访问该对象存在困难时可以通过一个代理对象来间接访问,为了保证客户使用的透明性,委托对象与代理对象需要实现相同的接口。
3.代理模式分类
3.1 静态代理
事例:银行办卡——角色划分
1.目标接口——IBank
2.代理对象——银行工作人员 (也就是我们的经纪人)
3.被代理对象——我们
public interface IBank {
/**
* 申请办卡
*/
void applyBank();
}
public class BankWorker implements IBank{
private IBank iBank;
//2.代理对象持有我们被代理对象的引用。
public BankWorker(IBank iBank){
this.iBank = iBank;
}
@Override
public void applyBank() {
System.out.println("开始办理");
iBank.applyBank();
System.out.println("办理完成");
}
}
public class My implements IBank{
private String name;
public My(String name) {
this.name = name;
}
@Override
public void applyBank() {
System.out.println(name + " 申请办卡");
}
}
1.使用
public class AgencyTest {
public static void main(String[] args){
My my = new My("姚明");
BankWorker bankWorker = new BankWorker(my);
bankWorker.applyBank()
}
}
2.执行结果
3.注意:
1.静态代理代理对象和被代理对象需要实现目标接口对象。
2.代理对象持有被代理对象的引用。
4.缺点:
1.当我们没添加新的功能的时候,都所有类都要修改。
5.UML图
3.2 动态代理
public interface IBank {
/**
* 申请办卡
*/
void applyBank();
/**
* 挂失银行卡
*/
void lostBank();
}
public class My implements IBank {
private String name;
public My(String name) {
this.name = name;
}
@Override
public void applyBank() {
System.out.println(name + " 申请办卡");
}
@Override
public void lostBank() {
System.out.println(name + " 申请挂失");
}
}
public class BankInvocationHandler implements InvocationHandler {
//被代理的对象
private Object object;
public BankInvocationHandler(Object object) {
this.object = object;
}
/**
* 目标接口每次执行的方法,都会调用该方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始办理");
//通过反射执行被代理对象的方法。
Object agencyObject = method.invoke(object,args);
System.out.println("办理完成");
return agencyObject;
}
}
1.使用
public class AgencyTest {
public static void main(String[] args){
//Java的静态代理 返回的是一个IBank的实例对象,是由Java给我们创建的
IBank bank = (IBank) Proxy.newProxyInstance(
IBank.class.getClassLoader(), //ClassLoader 类加载器
new Class<?>[]{IBank.class}, //代理对象接口(必须是接口)
new BankInvocationHandler());
//当调用对象的方法时候,就会调用 BankInvocationHandler中的invoke方法
bank.applyBank();
System.out.println("-------------------------");
bank.lostBank();
}
}
2.执行结果
3.注意:
1.当调用对象的方法时候,就会调用 BankInvocationHandler中的invoke方法
4.优点:
1.当我们没添加新的功能的时候,只需要修改被代理对象和invoke方法。
4.源码中的代理模式
1.Retrofit的源码:
1.主要就是通过动态代理将接口转换成一个实例对象,调用方法。
2.解析是方法的所有注解 @POST @GET @DELETE等等
3.解析是方法的参数注解 @Query @Path @Field等等
4.封装成Call对象,进行返回
public <T> T create(final Class<T> service) {
//1.检查是否是接口
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//2.动态代理设计模式
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//3.重点*具体执行细节
//method:就是我们调用的具体的方法(例如:login方法) 去解析方法属性和参数
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}