设计模式?牛不牛?B or no B? let us make B?
不扯淡了。入正题。
先假设一个场景,一个Tank类,我里面有一个move方法,我需要去检测调用move所用的时间。
定义一个功能接口:Moveable:
public interface Moveable { public void move(); }
建立一个Tank.java:
import java.util.Random; public class Tank implements Moveable{ public void move(){ long startTime = System.currentTimeMillis(); System.out.println("startTime:"+startTime); System.out.println("Tank is moving..."); try { Thread.sleep(new Random(47).nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis(); System.out.println("Time:"+(endTime-startTime)); } }
在方面内部前后加上一些逻辑,计算时间差。
然后再定义一个Client类去driver Tank
public class Client { public static void main(String args[]){ Tank tank = new Tank(); tank.move(); } }
ok,实现了Client to driver Tank and Calculation time.
打印内容:
startTime:1439783874008
Tank is moving...
Time:9259
假如说我没有这个move方法体,换句话说我得不到Tank类的具体实现,那我怎么在move方法前后加一些计算时间的逻辑代码呢?
有两种方法 继承和聚合
首先修改Tank.java,去掉move方法中的计算时间的前后逻辑代码
继承方法实现:
新建一个Tank1.java
public class Tank1 extends Tank{ @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("startTime:"+startTime); super.move(); long endTime = System.currentTimeMillis(); System.out.println("Time:"+(endTime-startTime)); } }
在Client中 new Tank1().move()就搞定了。
实现接口的方式(聚合的方式)
定义一个TankTimeProxy,作为代理类,这个代理类也实现Moveable接口,以便规范代码,让move方法继承下来。再定义一个Moveable的私有变量,用于外部传入一个Tank类的对象tank,以便在TankTimeProxy的move方法中去调用Tank类的move方法,从而实现实现代理。上代码:
public class TankTimeProxy implements Moveable { private Moveable t; public TankTimeProxy(Moveable t) { super(); this.t = t; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("startTime:"+startTime); t.move(); long endTime = System.currentTimeMillis(); System.out.println("Time:"+(endTime-startTime)); } }
Client类:
public class Client { public static void main(String args[]){ Tank tank = new Tank(); TankTimeProxy ttp = new TankTimeProxy(tank); ttp.move(); }
这样也实现了代理。
毫无疑问聚合的方式更好。为什么呢?
代理的实现是为了方便在某个方法前后去插拔一些逻辑代码,假如我不止一个需求呢?我需要在move方法中先打出一些log,然后再去计算时间?那我用继承的方法要怎么实现?
再写一个Tank2类,然后继承Tank1,重写move方法。
public class Tank2 extends Tank1{ public void move(){ System.out.println("log:get in move"); super.move(); } }
然后在Client中调用 new Tank2().move()
Console:
log:get in move
startTime:1439790468436
Time:9260
可以实现!但是我现在改需求了,我要先打印时间,再打日志。嗯,没事,我再写一个Tank3,实现日志代理,再写一个Tank4继承Tank3实现时间代理!嗯,解决了~
啪啪啪!!新的需求来了,要再加一个代理需求,用来验证登录信息。我去 ,我去拿个计算器算一下,我要写几个类 。。。。
明白我的意思了吧?继承实现代理会因为代理需求的执行顺序和个数 发生类爆炸!不可取!
现在来看看聚合方式的代理
新建一个代理类:
public class TankLogProxy implements Moveable{ private Moveable t; public TankLogProxy(Moveable t) { super(); this.t = t; } @Override public void move() { System.out.println("log:get in move"); t.move(); } }
在Client中
public class Client { public static void main(String args[]){ Tank t = new Tank(); TankTimeProxy ttp = new TankTimeProxy(t); TankLogProxy tlp = new TankLogProxy(ttp);
tlp.move(); } }
这样就实现了在时间代理外面套一层日志代理。
来来来我们改改代码
public class Client { public static void main(String args[]){ Tank t = new Tank(); TankLogProxy tlp = new TankLogProxy(t); TankTimeProxy ttp = new TankTimeProxy(tlp);
ttp.move(); } }
嗯,日志代理和时间代理的执行顺序改变,轻松实现。
我们接着看,为什么会这样?关键点在于代理类实现了Moveable接口,基类Tank也实现了Moveable,所以Tank可以传入到代理中,A代理类也可以传入到B代理类中,然后在B中实现move,调用A代理类的move方法之上加上B自己需要的逻辑代码。
天色不早了,先说到这里了。