zoukankan      html  css  js  c++  java
  • 设计模式之代理模式(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自己需要的逻辑代码。

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

  • 相关阅读:
    LINQ to SQL 运行时动态构建查询条件
    MVC ViewData和ViewBag
    下面介绍一下 Yii2.0 对数据库 查询的一些简单的操作
    php表单中如何获取单选按钮与复选按钮的值
    [moka同学摘录]Yii2.0开发初学者必看
    Yii路径总结
    css样式reset
    ajax onblur 用法
    jquery自定义插件——window的实现
    jQuery使用ajaxStart()和ajaxStop()方法
  • 原文地址:https://www.cnblogs.com/think-in-java/p/4736452.html
Copyright © 2011-2022 走看看