代理模式
代理模式
- 静态代理
- 动态代理
静态代理

- 抽象角色
Subject:可以是抽象类或者接口,包含了需要代理的方法 - 真实角色
RealSubject:被代理的角色 - 代理角色
Proxy:在Subject中抽象的方法都交给RealSubject处理,其它额外功能在Proxy中完成
代理角色和真实角色都实现了抽象接口中的方法,在客户实现需求时,只需要调用Proxy中的方法,不直接接触真实角色。
抽象角色
public interface Rent { public void rent(); }
真实角色
public class Host implements Rent {
@Override
public void rent() {
System.out.println("rent...");
}
}
代理角色
public class Proxy implements Rent {
private Host host;
public Proxy(){}
public Proxy(Host host){
this.host=host;
}
public void before(){
System.out.println("before...");
}
@Override
public void rent() {
before();
host.rent(); //核心功能(抽象接口中的方法)仍然由真实角色处理
after();
}
public void after(){
System.out.println("after...");
}
}
客户
public class Client {
@Test
public void rent(){
Host host=new Host();
Proxy proxy=new Proxy(host);
proxy.rent(); //客户只调用代理角色方法,不接触被代理角色
}
}
缺点:
- 一个代理类只服务于一个类或接口。程序中将产生多个代理类,服务不同的接口。
- 一旦该类增加方法,代理类和真实角色类都要实现增加的方法
动态代理
使用JDK的java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口
Proxy.newProxyInstance 生成动态代理类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException参数:
loader- 定义代理类的类加载器
interfaces- 代理类要实现的接口列表
h- 指派方法调用的调用处理程序返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
InvocationHandler.invoke处理代理实例上的方法,在自定义的继承InvocationHandler的子类中重写该方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
参数:
proxy- 在其上调用方法的代理实例
method- 对应于在代理实例上调用的接口方法的Method实例。Method对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args- 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为null。基本类型的参数被包装在适当基本包装器类(如java.lang.Integer或java.lang.Boolean)的实例中。返回:
从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为
null并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出ClassCastException。
抽象角色
public interface Rent { public void rent(); }
自定义代理实例的调用处理程序类
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target=target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
//处理代理实例上的方法并返回调用结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
//核心功能在真实角色中实现
Object result=method.invoke(target,args);
after();
return result;
}
//代理类上实现的额外功能
public void after(){
System.out.println("after...");
}
public void before(){
System.out.println("before...");
}
}
客户
public class Client {
@Test
public void dynamicProxy(){
Host host=new Host(); //真实角色
//代理实例的调用处理程序
ProxyInvocationHandler handler=new ProxyInvocationHandler();
handler.setTarget(host);
Rent rent= (Rent) handler.getProxy(); //代理角色
rent.rent();
}
}
优点:
- 抽象接口增加方法时,只需要在真实角色中实现,在代理类中不需要实现,统一由
invoke方法处理 - 一个代理类可以代理多个不同接口,通过
setTarget方法实现 - 动态代理更加灵活,代理类可以在程序运行时,通过反射动态生成,而不是由代码定义
参考:
https://blog.csdn.net/qq_33369905/article/details/105828919
https://www.jianshu.com/p/9cdcf4e5c27d
浙公网安备 33010602011771号