zoukankan      html  css  js  c++  java
  • [Java] 静态代理

    什么叫代理? 什么是静态代理?什么是动态代理?
     Java 动态代理模式 
    代理:一个角色代表另一个角色来完成某些特定的功能。 
       比如:生产商,中间商,客户这三者这间的关系  
                客户买产品并不直接与生产商打交道,也不用知道产品是如何产生的,客户只与中间商打交道,而中间商就可以对产品进行一些包装,提供一些售后的服务。
     * 代理模式有三个角色: 1. 抽象主题角色 2. 代理主题角色 3. 实际被代理角色
    下面我们来个一个静态代理的实现。 
    我以一个坦克为例。
     1, 现在我们来建立一个java项目,叫Proxy,建立一个类,叫Tank, 继续建立一个接口,
       叫 Moveable, 我们用 Tank 来实现 Moveable(意思就是坦克实现移动)
    抽象主题角色:Moveable 
    package com.bjsxt.proxy;
    
    public interface Moveable {
        void move();
    }
    代理主题角色:TanktimeProxy 
    package com.bjsxt.proxy;
    
    public class TankTimeProxy implements Moveable {
        
        Moveable t;
        
        public TankTimeProxy(Moveable t) {
            super();
            this.t = t;
        }
        
        @Override
        public void move() {
            long start = System.currentTimeMillis();
            System.out.println("starttime : " + start);
            t.move();
            long end = System.currentTimeMillis();
            System.out.println("time :  " + (end - start));
        }
    }
    
    实际被代理对象:Tank 
    package com.bjsxt.proxy;
    
    import java.util.Random;
    
    public class Tank implements Moveable {
    
        @Override
        public void move() {
            System.out.println("Tank Moving...");
            try {
                Thread.sleep(new Random().nextInt(10000)); // 产生  100  毫秒  (10秒 ) 以内的随机数
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    测试:TestTank.java
    package com.bjsxt.proxy;
    
    public class TestTank {
        public static void main(String[] args) {
            Tank t = new Tank();
            Moveable move = new TankTimeProxy(t);
            move.move();
        }
    }
      从上例可以看到代理主题角色:TanktimeProxy实现了对Tank的move()方法运行时间的计算,而TanktimeProxy,Tank都实现了Moveable接口,通过调用TanktimeProxy的move()方法我们可以实现对Tank的move()方法的运行时间的计算,而不用在Tank的move()方法中作任何实现,这就是代理的作用。代理实现时TanktimeProxy,Tank必需实现Moveable接口。

    下面我想在 TanK 的 move() 方法前后加上日志: 

       我必需再写一个类来实现这一功能:
    package com.bjsxt.proxy;
    
    public class TankLogProxy implements Moveable {
        
        Moveable t;
        
        public TankLogProxy(Moveable t) {
            super();
            this.t = t;
        }
    
        @Override
        public void move() {
            System.out.println("Tank start");
            t.move();
            System.out.println("Tank end");
        }
    }
    测试:
    package com.bjsxt.proxy;
    
    public class Client {
        public static void main(String[] args) throws Exception {
            
            Tank t = new Tank(); // 最初的代理对象
            TankTimeProxy ttp = new TankTimeProxy(t);
            TankLogProxy tlp = new TankLogProxy(ttp);
            Moveable m = tlp;
            /* 时间包日志
             *   
             *  TankLogProxy tlp = new TankLogProxy(t);      
             *  TankTimeProxy ttp = new TankTimeProxy(tlp);
             *  Moveable m = ttp;
             * 
             * */
            m.move();
        }
    }
    // 可以对任意的对象、任意的接口方法,实现任意的代理

      这样我通过代理在Tank的move()方法前后加入了日志和时间统计的功能,由于TanktimeProxy,TanklogProxy都实现了Moveable接口,所以TanklogProxy可以代理TanktimeProxy,反过来也可以,它们对Tank的代理顺序是可以交换的。 满足我们的要求,如果现在我们要先时间,再日志,我们只需要修改一下测试类就oK

    这上面的就可以叫静态代理

    现在有出现了一个问题?如果我现在有多个类,那我是不是要去实现多个计时,多个日志,那不是和刚才的继承一样,造成了类的大量产生(重复),这样显然是不合理的,那我们带怎么办喃?我们现在就可以使用动态代理

    如果我想在Tank的move()方法调用的前后加入更多的功能,是不是要写更多的代理主题角色,这样子会使得代码过于臃肿,不易于维护,那有没有什么办法可以解决呢,答案是可以的,我们可以动态的来生成代理主题角色,来代理所有的被代理对象,这就是动态代理。

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    动态代理-你不必知道我存在
        理解 Spring 的 AOP
    假设 :
      (1), 具备面向对象的设计思维
      (2), 了解多态的概念
      (3), 大致了解反射(非必须)

    真实案例
     (1), 想知道一个方法的运行时间
         @1), 继承 VS  聚合 (一个类有另一个类的对象)
     tank2 与 tank3 其实都是代理的方法。 tank2与tank3都是代理类

    Tank2.java

    package com.bjsxt.proxy;
    
    public class Tank2 extends Tank {
    
        @Override
        public void move() {
            long start = System.currentTimeMillis();
            super.move();
            long end = System.currentTimeMillis();
            System.out.println("time :  " + (end - start));
        }
    }

    继承实现代理有缺点。 实现interface的实现代理好



     这两个哪个好喃?

          如果现在我们还要增加一个日志的功能,如果是继承,我们还要写一个类来继承Tank2,但是用户又说,我要求先日志,在计算时间,那么是不是又要写个类来实现movaable接口,来修改喃,这样就会造成类的无限增长,这显然是不合理的,所以我们要用聚合。。聚合,无论你增加多少功能,我都可以互相交换.



  • 相关阅读:
    MySQL的安装问题
    初识二分法
    PK赛 lower_bound( )和upper_bound( )的应用
    记录
    "双指针"去重有序数组
    归并排序(循序渐进中......)
    [2021.4.20打卡]LeetCode781. 森林中的兔子
    杂记...(持续更新)
    [未完待续](c++实现)八数码Ⅱ
    [回忆向]快速排序(降序) 感悟
  • 原文地址:https://www.cnblogs.com/robbychan/p/3786558.html
Copyright © 2011-2022 走看看