我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情
简介
代理,是一个中间者的角色,它屏蔽了访问方和委托方之间的直接接触。
也就是说访问方不直接调用委托方的这个对象,而是通过实例化一个跟委托方有同样接口的代理方,通过这个代理方来完成对委托方的调用。访问方只和代理方打交道,这个代理方有点像掮客的角色。现实生活中代理好比房产中介。
什么时候需要用到代理模式呢?
- 访问方不想和委托方直接接触,或者直接接触有困难。
- 访问方对委托方的访问需要增加额外处理,比如访问前和访问后都做一些处理。这种情况下我们不能直接对委托方的方法进行修改,这样同样违反了开闭原则。
代理模式有两类:静态代理和动态代理,下面我们分别通过代码详细说明。
静态代理
静态代理主要是代理类需要每次都要手工创建。
private interface ICar {
void move();
}
private class Benz implements ICar {
@Override
public void move() {
ToastUtil.showToast("Benz move");
}
}
//代理类
private class BenzProxy implements ICar {
private Benz benz;
public BenzProxy() {
benz = new Benz();
}
@Override
public void move() {
//做一些前置工作,比如检查车辆的状况
//before();
benz.move();
//做一些后置工作,比如检查结果
//after();
}
}
//调用
BenzProxy proxy1 = new BenzProxy();
proxy1.move();
动态代理
动态代理的代理类可以根据委托类自动生成,而不需要像静态代理那样通过手工创建。代理类的代码不是在java代码中定义的,而是在运行的时候动态生成的。
//动态代理类
public class CarHandler implements InvocationHandler {
//目标类的引用
private Object target;
public CarHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//做一些前置工作,比如检查车辆的状况
before();
//调用被代理类的方法
Object result = method.invoke(target, args);
//做一些后置工作,比如检查结果
//after();
return result;
}
private void before() {
ToastUtil.showToast("before Benz move");
}
}
//调用方
ICar car1 = new Benz();
InvocationHandler handler = new CarHandler(car1);
ICar proxy2 = (ICar) Proxy.newProxyInstance(ICar.class.getClassLoader(), new Class[]{ICar.class}, handler);
proxy2.move();
动态代理+简单工厂
接着上面动态代理调用方的使用方式,我们可以通过工厂模式,加上泛型,优化一下动态代理的生成和调用。
public class ProxyFactory<T> {
private T client;//目标对象
private IBefore before; // 前置增强
private IAfter after; // 后置增强
@SuppressWarnings("unchecked")
public <T> T createProxy() {
ClassLoader loader = client.getClass().getClassLoader();
Class[] interfaces = client.getClass().getInterfaces();
InvocationHandler h = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("getName".equals(method.getName())){
//可根据name值过滤方法
}
//前置
if (before != null) {
before.doBefore();
}
Object result = method.invoke(client, args);//执行目标对象的目标方法
if (after != null) {
after.doAfter();
}
return result;
}
};
return (T) Proxy.newProxyInstance(loader, interfaces, h);
}
public void setClient(T client) {
this.client = client;
}
public void setBefore(IBefore before) {
this.before = before;
}
public void setAfter(IAfter after) {
this.after = after;
}
}
public interface IBefore {
void doBefore();
}
public interface IAfter {
void doAfter();
}
//调用
ProxyFactory factory = new ProxyFactory();//创建工厂
factory.setBefore(new IBefore() {
@Override
public void doBefore() {
System.out.println("doBefore.");
}
});
factory.setClient(new Benz());
factory.setAfter(new IAfter() {
@Override
public void doAfter() {
System.out.println("doAfter.");
}
});
ICar car2 = (ICar) factory.createProxy();
car2.move();
动态代理拓展:AOP
Aspect-Oriented Programming,面向切面编程。
AOP的实现就是用了动态代理。
简单来说,AOP就是能够动态地将代码切入到指定的位置,在指定位置上实现编程,从而达到动态改变原有代码的行为。
上面的IBefore和IAfter接口实际上就是实现了简单的AOP,比如在invoke具体方法之前和之后,我们可以插入一些操作。
Proxy.newProxyInstance
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
loader: 委托类的classLoader;
interfaces: 代理类需要实现的接口,这个接口同委托类的接口;
h: 调用处理器,只有一个invoke方法,调用委托类的任何方法都是通过它的invoke方法。