问题背景:我们想对一个动作进行记录,记录的方式可能有多种,记录的顺序也有多种,例如:
这是一种记录方式
Controller Start:chouwu
start time: 1458124189349
Tank Start....
//Tank Moving这句是要被记录的动作
Tank Moving....
Tank Stop.....
end time: 1458124189395
Controller End:chouwu
这是另一种记录方式
Controller Start:chouwu
Tank Start....
start time: 1458124392063
//Tank Moving这句是要被记录的动作
Tank Moving....
end time: 1458124395385
Tank Stop.....
Controller End:chouwu
也有可能是这样的
Tank Start....
start time: 1458124479626
Controller Start:chouwu
//Tank Moving这句是要被记录的动作
Tank Moving....
Controller End:chouwu
end time: 1458124486154
Tank Stop.....
上述三种分别为LogProxy,TimeProxy,ControllerProxy,不仅它们的顺序会调换,可能还需要添加新的记录Proxy,还可能将Tank换成Car,有什么简单的修改方法能得到随心所欲的调换和添加?
使用动态代理设计模式!
模式还是需要通过代码来理解:
Moveable接口
package com.chouwu;
public interface Moveable {
void move();
}
实现了Moveable接口的Tank
package com.chouwu;
import java.util.Random;
public class Tank implements Moveable {
@Override
public void move() {
try {
System.out.println("Tank Moving....");
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
实现了Moveable接口的Car(Car和Tank区别很小,只是为了说明Moveable对象可调换)
package com.chouwu;
import java.util.Random;
public class Car implements Moveable {
@Override
public void move() {
try {
System.out.println("Car Moving....");
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
实现了Moveable接口的LogProxy
package com.chouwu;
public class LogProxy implements Moveable{
Moveable m;
public LogProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("Tank Start....");
m.move();
System.out.println("Tank Stop.....");
}
}
实现了Moveable接口的TimeProxy
package com.chouwu;
public class TimeProxy implements Moveable{
Moveable m;
public TimeProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
long start = System.currentTimeMillis();
System.out.println("start time: " + start);
m.move();
long stop = System.currentTimeMillis();
System.out.println("end time: " + stop);
}
}
实现了Moveable接口的ControllerProxy
package com.chouwu;
public class ControllerProxy implements Moveable{
Moveable m;
String controller;
public ControllerProxy(Moveable m,String controller) {
this.m = m;
this.controller = controller;
}
@Override
public void move() {
System.out.println("Controller Start:"+controller);
m.move();
System.out.println("Controller End:"+controller);
}
}
注意,如何调换和更改记录的方式主要在主程序Client中,Client如下:
如果我记录Tank的行为,只记录时间和日志,并且先记录时间,后记录日志,那么Client中就这样调用:
package com.chouwu;
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
LogProxy lp = new LogProxy(t);
TimeProxy tp = new TimeProxy(lp);
tp.move();
}
}
结果如下
start time: 1458125789924
Tank Start....
Tank Moving....//这句是要被记录的动作
Tank Stop.....
end time: 1458125799718
如果我记录Tank的行为,记录时间、日志和控制者,并且先记录日志,后记录控制者和时间,那么Client中就这样调用:
package com.chouwu;
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
TimeProxy tp = new TimeProxy(t);
ControllerProxy cp = new ControllerProxy(tp,"chouwu");
LogProxy lp = new LogProxy(cp);
lp.move();
}
}
结果
Tank Start....
Controller Start:chouwu
start time: 1458126074329
Tank Moving....
end time: 1458126076182
Controller End:chouwu
Tank Stop.....
如果有天有新的需求,需要我记录另一种实现了Moveable的类Car的行为,也是记录时间、日志和控制者,并且先记录时间,后记录日志,那么Client中就这样调用:
package com.chouwu;
public class Client {
public static void main(String[] args) {
// Tank t = new Tank();
Car c = new Car();
TimeProxy tp = new TimeProxy(c);
ControllerProxy cp = new ControllerProxy(tp,"chouwu");
LogProxy lp = new LogProxy(cp);
lp.move();
}
}
结果:
Tank Start....
Controller Start:chouwu
start time: 1458126212160
Car Moving....
end time: 1458126217843
Controller End:chouwu
Tank Stop.....
由上可见,动态代理十分灵活的帮助我们实现了调序和随时增删代理的功能。Moveable统一了除测试外的所有的类,每个代理类中都聚合了一个实现了Moveable接口的对象,或是另一个代理,或是被代理的对象。当然,理解动态代理模式还是要依靠自己动手写程序来理解。