一天一种设计模式之五-----代理模式

一.代理模式简介

  1. 代理模式属于结构型模式java

  2. 定义:代理模式为其余对象提供一种代理以控制对这个对象的访问。编程

  3. 代理模式是java框架层面应用最普遍的少数几种设计模式之一,很是重要。设计模式

  4. 适用场景:安全

    1. 远程代理,为一个对象在不一样的地址空间提供局部表明,这样能够隐藏一个对象存在于不一样地址空间的事实。性能优化

    2. 虚拟代理,根据须要建立开销很大的对象,经过它来存放实例化须要很长时间的对象,这样能够达到性能优化;框架

    3. 安全代理,用来控制真实对象访问时的权限。通常用于对象应该有不一样的访问权限的时候;ide

    4. 智能指引,是指当调用真实的对象的时候,代理处理另外的一些事情(用的比较多)性能

  5. 代理模式要求代理实现与被代理对象相同的接口(cglib与被代理对象是子类与父类的关系),以保证任什么时候候都能代替真实对象。这也是它与适配器模式的区别!!测试

  6. 代理模式普遍应用于aop编程。可以在不改变源代码的前提下提供统一的日志管理,先后置拦截器,符合开放封闭原则、依赖倒置原则,优化

二.测试代码

  1.     下面代码属于静态代理,大体场景是追求者会追妹子,但他不认识某girl,而经过代理类认识,因此追求者经过代理类对妹子展开了追求。

  2. public class ProxyTest {
        public static void main(String[] args) {
            PursuitWay pursuitWay=new Proxy(new Pursuiter(new Girl("小白")));
            pursuitWay.giveFlower();
            pursuitWay.giveGift();
        }
    }
    interface PursuitWay{
        void giveFlower();
        void giveGift();
    }
    class Girl{
        private String name;
        public Girl(String name) {
            this.name=name;
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
    }
    class Pursuiter implements PursuitWay{
        Girl girl;
        public Pursuiter(Girl girl){
            this.girl=girl;
        }
        @Override
        public void giveFlower() {
            System.out.println("追求者送"+girl.getName()+"花");
        }
    
        @Override
        public void giveGift() {
            System.out.println("追求者送"+girl.getName()+"礼物");
        }
        
    }
    
    class Proxy implements PursuitWay{
        PursuitWay pursuter;
        public Proxy(PursuitWay pursuiter){
            this.pursuter=pursuiter;
        }
        @Override
        public void giveFlower() {
            pursuter.giveFlower();
        }
    
        @Override
        public void giveGift() {
            pursuter.giveGift();
        }
        
    }
  3. 既然是经过代理去追妹子,那每次苦力活代理作作日志,设置个障碍就不难理解了吧。

  4. 上述功能若是要经过适配器模式实现,则proxy没必要非要实现PursuitWay,它会有本身的方法而没必要非要是giveXXX,只须要在它本身的方法中实现pursuter的giveXXX方法就能够了,具体代码略。

  5. 上述代理模式属于静态代理,由于代理类是咱们本身编写出来的,而动态代理则是经过java虚拟机,在运行期间生成的字节码。

  6. 下述代码是经过动态代理实现的相同功能

      1.   获取追求者上的全部接口列表;
        2.   肯定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;

        3.   根据须要实现的接口信息,在代码中动态建立 该Proxy类的字节码;

        4 .  将对应的字节码转换为对应的class 对象;

        5.   建立InvocationHandler 实例handler,用来处理Proxy全部方法调用;

        6.   Proxy 的class对象 以建立的handler对象为参数,实例化一个proxy对象

  7. public class ProxyTest {
        public static void main(String[] args) {
            Class clazz=Proxy.getProxyClass(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces());
            System.out.println("proxy类为"+clazz.getName());
            System.out.println("proxy实现的接口有"+clazz.getInterfaces()[0].getName());
            System.out.println("-----开始生成代理对象(实际上该代理对象就是一个该接口的实现类)");
            PursuitWay pursuter=(PursuitWay) Proxy.newProxyInstance(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces(), new MyInvocationHandler(new Pursuiter(new Girl("小白"))));
            pursuter.giveFlower();
            pursuter.giveGift();
        }
    }
    interface PursuitWay{
        void giveFlower();
        void giveGift();
    }
    class Girl{
        private String name;
        public Girl(String name) {
            this.name=name;
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
    }
    class Pursuiter implements PursuitWay{
        Girl girl;
        public Pursuiter(Girl girl){
            this.girl=girl;
        }
        @Override
        public void giveFlower() {
            System.out.println("追求者送"+girl.getName()+"花");
        }
    
        @Override
        public void giveGift() {
            System.out.println("追求者送"+girl.getName()+"礼物");
        }
        
    }
    class MyInvocationHandler implements InvocationHandler{
        Object object;
        public MyInvocationHandler(Object object){
            this.object=object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            return method.invoke(object, args);
        }
        
    }
  8. 上述代码经过jdk自带的代理类实现,它和静态代理类有一样的局限性,就是要求被代理类必须有一个或者多个对应具体业务逻辑的接口。myInvocationHandler里边的invoke方法中能够提供拦截、写日志等功能。

  9. cglib包的代理类CglibProxy是针对某个类生成一个子类,该子类天然会包括其父类的全部业务逻辑方法。并且不在局限于必须有上层接口。可是cglib包也要求被代理类不能为final类,不然继承不了,测试代码和动态代理很像,略。

  10. cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,理论上比使用Java反射效率要高,不过有大神曾经测试过,貌似性能差很少,并且jdk的动态代理还要比cglib效率高一点点。有兴趣的朋友能够去试试。

  11. 欢迎大神交流意见。

  12. 下一节将会讲解工厂方法模式,该模式在service层应用很广泛。敬请期待。

相关文章
相关标签/搜索