当实现同一个接口的很多类需要进行同样的操作,我们需要重复写很多代码,这个时候我们可以使用代理模式,减少代码的冗余,增加代码的层次感。比如我们需要统计一个接口的运行时间:
接口类
public interface Dongwu {
public void eat(String str);
public void drink(String str);
public void play(String str);
}
实现类
public class Dogs implements Dongwu{
@Override
public void eat(String str) {
System.out.println("一只狗在吃狗粮【"+str+"】");
}
@Override
public void drink(String str) {
System.out.println("一只狗在喝水【"+str+"】");
}
@Override
public void play(String str) {
System.out.println("一只狗在玩球【"+str+"】");
}
}
public class Pig implements Dongwu{
@Override
public void eat(String str) {
System.out.println("一只猪在吃猪食【"+str+"】");
}
@Override
public void drink(String str) {
System.out.println("一只猪喝水【"+str+"】");
}
@Override
public void play(String str) {
System.out.println("一只猪玩球【"+str+"】");
}
}
代理类
/**
* 动物接口静态代理类
* @author
*
*/
public class DongWuProxy implements Dongwu{
public Dongwu dw;
public DongWuProxy(Dongwu dw) {
super();
this.dw = dw;
}
@Override
public void eat(String str) {
long starTime = System.nanoTime();
dw.eat(str);
long endTime = System.nanoTime();
System.out.println("方法耗时(纳秒):" + (endTime - starTime));
}
@Override
public void drink(String str) {
long starTime = System.nanoTime();
dw.drink(str);
long endTime = System.nanoTime();
System.out.println("方法耗时(纳秒):" + (endTime - starTime));
}
@Override
public void play(String str) {
long starTime = System.nanoTime();
dw.play(str);
long endTime = System.nanoTime();
System.out.println("方法耗时(纳秒):" + (endTime - starTime));
}
}
测试类
public class DongwuTest {
public static void main(String[] args) {
DongWuProxy d = new DongWuProxy(new Pig());
d.drink("小猪1号");
DongWuProxy dd = new DongWuProxy(new Dogs());
dd.drink("小猪2号");
}
}
一只猪喝水【小猪1号】
方法耗时(纳秒):449400
一只狗在喝水【小猪2号】
方法耗时(纳秒):120300
当我们接口很多的时候,我们就需要写很多代理类而且得写很多代理方法,这个时候我们就需要用到动态代理来优化替代。
我们经常使用的框架如spring mybatis status 等都用到了动态代理
动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CostInvocationTimeHandler implements InvocationHandler{
private Object target;
public CostInvocationTimeHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long starTime = System.nanoTime();
Object result = method.invoke(this.target, args);// @1
long endTime = System.nanoTime();
System.out.println( "方法耗时(纳秒):" + (endTime - starTime));
return result;
}
/**
* 用来创建targetInterface接口的代理对象
*
* @param target
* 需要被代理的对象
* @param targetInterface
* 被代理的接口
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Object target, Class<T> targetInterface) throws Throwable {
if (!targetInterface.isInterface()) {
throw new IllegalStateException("targetInterface必须是接口类型!");
} else if (!targetInterface.isAssignableFrom(target.getClass())) {
throw new IllegalStateException("target必须是targetInterface接口的实现类!");
}
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new CostInvocationTimeHandler(target));
}
}
测试类
public class DongwuTest {
private Pig p = new Pig();
public static void main(String[] args) {
DongwuTest d = new DongwuTest();
d.test();
}
void test() {
Dongwu d;
try {
d = CostInvocationTimeHandler.createProxy(p, Dongwu.class);
d.drink("小猪1号");
d.eat("小猪2号");
d.play("小猪3号");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
一只猪喝水【小猪1号】
方法耗时(纳秒):459600
一只猪在吃猪食【小猪2号】
方法耗时(纳秒):37500
一只猪玩球【小猪3号】
方法耗时(纳秒):73400
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
因为代理类继承了InvocationHandler,根据继承机制,不能再有父类,所以动态代理只能对接口代理。