import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理模式
*/
public class Main {
public static void main(String[] args) {
System.out.println("静态代理");
ICat cat1 = new Cat();
ProxyCat proxyCat1 = new ProxyCat(cat1);
proxyCat1.run();
System.out.println("动态代理");
ICat cat2 = new Cat();
ICat proxyCat2 = (ICat)Proxy.newProxyInstance(Cat.class.getClassLoader(), Cat.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before running");
String result = (String) method.invoke(cat2,args);
System.out.println("after running");
return result;
}
}
);
proxyCat2.run();
}
}
public interface ICat {
void run();
}
public class Cat implements ICat {
@Override
public void run() {
System.out.println("running");
}
}
public class ProxyCat implements ICat{
ICat cat;
public ProxyCat(ICat cat){
this.cat = cat;
}
@Override
public void run() {
System.out.println("before running");
cat.run();
System.out.println("after running");
}
}
问题:
如果你有一个接口方法,你想在接口调用的前后做一些事情,比如打印日志,但是又不想改之前的代码,怎么做?
用法:
可以用代理设计模式,静态代理很简单了,自己看,但是静态代理每写一个代理就要增加一个类,比较麻烦,其实代理模式无非就是指定一个对象的方法,在它前后加代码,如果我们把接口和作用对象作为参数,不就可以实现这个需求了吗,传这种元数据很自然就想到反射这堆知识了,所以java的reflect包里已经给我们准备好了,直接用就好,这个代码已经够简单了,比网上所有文章的动态代理例子都要简单了,但是如果实际生产环境还是要封装的,其实技术都是很简单的,只是传播技术的人表达方式和我们正常的思考方式时经常不在一个频道上,才导致了技术看起来很难,所以我们才需要多看书,把自己的大脑思维变成计算机思维,才方便接受更多的知识。
接着说,又到重点了,代理和装饰器模式很像吧,只看功能几乎是一样的,最大的重点在于思维,代理重在控制,而装饰器重在对结果的利用,简单点说,如果适配的接口都有返回结果,那么代理模式是不改代理接口返回的结果的,而装饰器必然要修改这个结果,spring的AOP如果你打印日志就是是代理模式,如果你用于结果透明修改,那就是装饰器模式,是不是听起来很玄学。
所以可以这么说,代理是一种特殊的装饰器模式,如果这个能理解的话,代理模式和适配器模式的区别也就弄明白了。