设计模式之代理模式 | Enplee's blog
0%

设计模式之代理模式

设计模式之代理模式

定义
1
2
给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
通俗的讲,就是本来是调用者和被调用者之间的直接交互,现在把调用者和被调用者分离,由代理来负责和调用者之间交互。
问题引入
1
2
3
当前实现了一个Tank类,Tank类实现了Movable接口,Movable接口定义了一个方法run();
调用Tank类实现的run方法,坦克会run,"Tank moving".
现在需求是,想要对run方法做一些banchMark性能测试,需要了解run方法的运行时间。
1
2
3
public interface Movable {
public void run();
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Tank implements Movable {
@Override
public void run() {
long start = System.currentTimeMillis();

System.out.println("Tank moving...");
try {
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
源码修改or继承
1
2
最为直观也最简单的方式就是直接修改源码,打印运行时间。
问题:缺点也很明显,很多方法的源码并不会暴露。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void run() {
long start = System.currentTimeMillis();

System.out.println("Tank moving...");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
1
2
3
采用继承的方式,构造一个子类继承自Tank来实现计算运行时间。
问题:每新增一个功能就要实现一个子类,实际生产中,新增的需求肯定不止计算时间一种;
当多种需求存在时,需要实现多个子类,更不用谈这些功能之间的组合了。
1
2
3
4
5
6
7
8
9
class Tank2 extends Tank{
@Override
public void run() {
long start = System.currentTimeMillis();
super.run();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
}
静态代理
1
2
3
4
代理和被代理对象实现相同的接口,代理的持有该接口类型的字段,字段的值是被代理的对象。
代理实现接口的方法,在增加功能的同时,执行字段中被代理对象的方法。
代理字段类型是接口,同时代理也是接口的实现,可以使得代理直接也可以互相代理。实现功能的组合。
问题:所有的代理只能针对一个接口实现。不能根据传入的对象动态生成代理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TankTimesProxy implements Movable {
Movable movable; //字段持有的是接口 实现既可以被别人代理
//也可以代理别的代理
public TankTimesProxy(Movable movable) {
this.movable = movable;
}

@Override
public void run() {
long start = System.currentTimeMillis();
movable.run();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
动态代理:JDK实现
1
2
3
动态代理不关心target对象,在运行期间动态的利用反射和ASM生成proxy。
java JDK的reflect包中提供了动态代理生成的解决方案。不需要第三方,功能相对较弱。
问题:所代理的target对象必须实现一个或者多个接口。
1
2
3
4
5
6
7
public static void main(String[] args) {
Movable proxy = (Movable)Proxy.newProxyInstance(
Tank.class.getClassLoader(),
Tank.class.getInterfaces(),
new LogHandler(new Tank()));
proxy.run();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class LogHandler implements InvocationHandler {
Tank tank;

public LogHandler(Tank tank) {
this.tank = tank;
}
public void before(Method method){
System.out.println("Method:"+method.getName()+" start...."); //进一步分离代理行为
}
public void end(Method method){
System.out.println("Method:"+method.getName()+" end...");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 其中三个参数,proxy代理对象本身,method被代理对象执行的方法,args方法执行参数
before(method);
Object o = method.invoke(tank, args);
end(method);
return o;

}
}
1
2
3
4
5
6
JDK的实现是利用Proxy的newProxyInstance()方法动态创建了Proxy。
此方法传入三个参数,第一个参数是Classloader被代理对象的类加载器;
InterFace[]被代理对象的所有实现接口集合;
以及最后一个InvocationHandler是定制函数执行的处理。
动态代理是通过底层是通过ASM(Java 字节码操控框架,动态生成类或者增强既有类的功能)直接生成的二进制class文件,
可以通过反编译,来了解proxy的构成。
1
2
//保存proxy
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public final class $Proxy0 extends Proxy implements Movable {//proxy实现了Moveble接口
private static Method m3;

public $Proxy0(InvocationHandler param1) {
//Proxy父类上的字段保存在Proxy.newProxyInstence的第三个参数 InvocationHandler实例
super(var1);
}

public final void run() {
try {
//代理功能的实现,实际上就是执行了我们自定义的invoke函数
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

static {
try {
//通过反射获得Method run
m3 = Class.forName("enplee.DesignPattern.Proxy.V5.Movable").getMethod("run");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
1
2
3
4
5
6
7
public class Proxy implements java.io.Serializable {
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
}
-------------本文结束感谢您的阅读-------------