转载

设计模式之代理模式(1)

设计模式?牛不牛?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自己需要的逻辑代码。

天色不早了,先说到这里了。

正文到此结束
Loading...