设计模式之代理模式(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自己需要的逻辑代码。

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

原文地址:https://www.cnblogs.com/think-in-java/p/4736452.html