学习动态代理stepbystep(1)

想学一下动态代理,看某人的视频教学,将资料整理如下:


一:有关代理,准确地说,是认识静态代理。


1.

有一个类:Tank,它里面有一个方法,随机睡眠。
import java.util.Random;
public class Tank {
public void move() {
System.out.println("Tank moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

现在,想知道它睡眠的时间
最简单的方法是在它的上下各加上代码:
long start = System.currentTimeMillis();

long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end-start));

2.
但有问题,由于测试一个功能的执行时间,通常是我们developer来做的,所以,如果采用这样的方法,导致的结果就是
我们需要附加大量的测试代码。每个方法加个监视,加不起啊。。。。。

解决方案:再定义一个类,继承之,并调用父类的方法,这样,就可以实现不改变底层代码而实现监听了。
public class Tank2 extends Tank{
@Override
public void move(){
long start = System.currentTimeMillis();
super.move();
long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end-start));
}
}

这,就是传说中的代理了。准确地说,是两种代理方式中的其中一种,即继承方式。
(由于调用tank2的方法时,实际调用的是tank,即它父类的方法,所以,我们可以把tank2看作是tank的代理)

测试:
public class Client {
public static void main(String[] args) {
System.out.println("继承实现方法");
Moveable m = new Tank2();
m.move();
}
}
产生的问题:Java是单继承啊,这样一个类岂不是只能对特定的类来实现监听功能了?而且,如果一个类既有计时监听,又有日志监听,
又想灵活调用顺序,那子类岂不更多了?

3.
的确啊,所以呢,我们又学习到了另一种代理:聚合代理。它的原理不是继承了,而实现接口。
所以聚合:就是说,在一个类中,存在另一个类的对象。
这样呢,在所有实现指定0接口的对象中,我们就可以灵活调用了。。于是乎:
改之:
public interface Moveable {
public void move();
}

import java.util.Random;
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

// 此类中,对于tank3调用的方法其实都是调用的tank的方法。因此,tank3也就是tank的代理。此类用于简单说明聚合的代理方式
public class Tank3 implements Moveable{
/*通过构造方法,来指定要监视哪个实现了Moveable接口的类
这里选的是Tank类。*/
///Tip:让myEclipse自动生成构造方法:source --> generate cons……
public Tank3(Tank t) {
super();
this.t = t;
}
Tank t;
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end-start));
}
}

下面:写测试类:
System.out.println("聚合的实现方法");
Moveable m = new Tank3(new Tank());
m.move();

4.用聚合来实现代理的灵活操作:
Moveable.java
Tank.java
////实现接口
public class TankTimeProxy implements Moveable{
/////参数可以是任何实现了Moveable的对象
public TankTimeProxy(Moveable t) {
super();
this.t = t;
}

/* 将参数改为Moverbale类型,这样不止是可以实现对Tank的监听
* Tank t;
*/
Moveable t;
@Override
public void move() {
long start = System.currentTimeMillis();
///实际是调用t的move方法
System.out.println(start);
t.move();
long end = System.currentTimeMillis();
System.out.println(end);
System.out.println("运行时间:" + (end-start));
}
}
////实现接口
public class TankLogProxy implements Moveable{
public TankLogProxy(Moveable t) {
super();
this.t = t;
}
// Tank t;
Moveable t;
@Override
public void move() {
System.out.println("(log)Tank start......");
t.move();
System.out.println("(log)Tank stop......");
}
}

client:
System.out.println("外层日志,里层时间);
Tank t = new Tank();
TankTimeProxy ttp = new TankTimeProxy(t);
TankLogProxy tlp = new TankLogProxy(ttp);
Moveable m = tlp;
m.move();//多态

out: 外层日志,里层时间
(log)Tank start......
1318846823046
Tank moving...
1318846829187
运行时间:6141
(log)Tank stop......

client:
System.out.println("外层时间,里层日志");
Tank t = new Tank();
TankLogProxy tlp = new TankLogProxy(t);
TankTimeProxy ttp = new TankTimeProxy(tlp);
Moveable m = ttp;
m.move();//多态

out: 外层时间,里层日志
1318847065609
(log)Tank start......
Tank moving...
(log)Tank stop......
1318847068265

运行时间:2656


又有新问题了:
如果Moveable中还有一个方法,shoot。
则在TankTimeProxy中,又要重写shoot方法。
加上System.out,再加上t.shoot(),再加上输出。


@Override
public void shoot(){
System.out.println(start);
t.shoot();
long end = System.currentTimeMillis();
System.out.println(end);
System.out.println("运行时间:" + (end-start));
}
(
此时有个Tip:当程序中有很多重复代码时,可以单独提出来,这样,在以后修改的时候就方便了。
如上:把System.out.println(start); 写成一个方法
System.out.println(end);
System.out.println("运行时间:" + (end-start)); 写成一个方法
)


这样对每个方法,第一个类,都需要一个代理。
因此,现在希望,找到一个代理TimeProxy,可以成为任意类的计时器,并可以在任意的方法上都可以直接加上。


你可能感兴趣的:(动态代理)