定义
代理模式又称为委托模式,它可以为其他对象提供一种代理以控制对这个对象的访问。我们可以通过代理对象间接访问被代理对象,代理对象和被代理对象需要实现相同的接口。代理模式在生活中很常用,比如外卖员帮我们送餐,律师帮我们打官司,或者是银行大堂经理帮我们办业务,都是代理模式的实现。
UML类图
代理模式的角色
-
Subject
抽象主题,代理类和被代理类都需要实现该接口。
-
ConcreteSubject
委托类,实现了抽象主题接口。
-
ProxySubject
代理类,也实现了抽象主题接口,并且在构造中传入了委托类对象,这样就可以调用委托类的方法。
示例
静态代理
静态代理需要自行定义代理对象,这里以去银行办理业务为例,抽象出申请卡和注销卡操作为IBank接口。
/**
* 定义委托类和代理类共同的接口方法(接口或者抽象类)
* 相当于是委托类和代理类行为的抽象
*/
public interface IBank {
void applyCard();
void cancelCard();
}
定义委托类和代理类
/**
* 委托类,执行具体的业务逻辑方法
*/
public class Man implements IBank {
@Override
public void applyCard() {
System.out.println("客户填单,申请办卡");
}
@Override
public void cancelCard() {
System.out.println("客户填单,申请挂失");
}
}
/**
* 代理类,该类持有委托类的引用,在其实现的方法中调用委托类中
* 相应的接口方法执行,起到代理的作用
*/
public class BankManager implements IBank {
private IBank man;
/**
* 构造方法中传入委托类
* @param man
*/
public BankManager(IBank man){
this.man = man;
}
@Override
public void applyCard() {
System.out.println("银行经理,问询客户需求");
//调用委托类对应的接口方法
man.applyCard();
System.out.println("欢送客户");
}
@Override
public void cancelCard() {
System.out.println("银行经理,问询客户需求");
man.cancelCard();
System.out.println("欢送客户");
}
}
在客户端实例化委托类,并将其传入代理类,调用代理方法
public class Client {
public static void main(String []args){
Man man = new Man();
//将委托类传入代理类
BankManager manager = new BankManager(man);
//调用代理类的接口方法
manager.applyCard();
manager.cancelCard();
}
}
动态代理
相对于静态代理,动态代理在编码阶段不需要编写代理类,而是通过反射机制动态的生成代理者的对象的,Java提供了InvocationHandler接口,通过实现该接口可以完成动态代理,具体实现如下,还是代理Man对象。
/**
* 实现InvocationHandler接口,构造方法中传入委托类
* invoke方法中调用委托类的方法
*/
public static class BankInvocationHandler implements InvocationHandler{
private Man man;
public BankInvocationHandler(Man man){
this.man = man;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("接待客户");
Object object = method.invoke(man,args);
System.out.println("欢送客户");
return object;
}
}
public class Client {
public static void main(String[]args){
Man man = new Man();
//调用newProxyInstance方法获得代理类
IBank proxy = (IBank) Proxy.newProxyInstance(
IBank.class.getClassLoader(),
new Class<?>[]{IBank.class},
new BankInvocationHandler(man)
);
//调用代理类的方法
proxy.applyCard();
proxy.cancelCard();
}
调用代理类的方法时,会执行到InvocationHandler的invoke方法,在这个方法中又调用了委托类对应的方法,可以添加我们自己的逻辑,这就完成了对Men对象的代理。
Android源码中的代理模式
Retrofit网络请求框架就是使用了动态代理的方式,代理了网络请求接口完成的网络请求。具体Retrofit源码分析看Android源码学习-Retrofit源码浅析。