zoukankan      html  css  js  c++  java
  • java设计模式自我总结---代理模式

      代理模式是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介。

      这里有也很详细的讲解:代理模式

       Spring 的AOP面向切面就是使用动态代理模式来实现的;

       打个比方说:我要买房,但是我对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人(中介)去帮我找,此处的代理就是这个意思。

      代理类分为静态代理类和动态代理类:

      首先看下静态代理类,代码如下:

      接口:

    public interface Source {
        void method();
    }

      委托类:

    /**
     * 委托类
     */
    public class RealSubject implements Source {
        @Override
        public void method() {
            System.out.println("我要去买房了");
        }
    }

      1、静态代理类:

    /**
     * 静态代理类
     */
    public class ProxySubject implements Source{
    
        private RealSubject realSubject;
    
        public ProxySubject() {
            this.realSubject = new RealSubject();
        }
    
        @Override
        public void method() {
            before();
            realSubject.method();
            after();
        }
    
        void before(){
            System.out.println("找房");
        }
    
        void after(){
            System.out.println("买房后装修");
        }
    }

      测试类:

    public class Text {
        public static void main(String[] args) {
            Source source = new ProxySubject();
            source.method();
        }
    }

      输出结果:

    找房
    我要去买房了
    买房后装修

      静态代理总结:

      优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

      缺点:我们得为每一个服务都创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。

       2、动态代理类

      动态代理类中我们不需要手动的创建代理类,我们只需要手动的编写一个动态处理器就可以了,真正的代理对象由JDK在运行时为我们动态的进行创建;

      Dynamic代理模式相对于静态代理,大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度;

      动态代理的实现依靠于InvocationHandler接口和Proxy类来实现的,每一个动态代理类中都必须要实现InvocationHandler接口,该接口中有唯一的invoke()方法;

      该方法的作用就是得到一个动态的代理对象,其接收三个参数:

    loader:  第一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    
    interfaces:  第二个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    
    h:  第三个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

      我们来看一下代码:

      首先定义一个接口,有两个方法

    public interface Source {
        void describe();
        void buyHourse();
    }

      给该接口定义一个实现类,其实就是我们的委托对象 

    public class SourceImpl implements Source {
        @Override
        public void describe() {
            System.out.println("中國風");
        }
        @Override
        public void buyHourse() {
            System.out.println("购房");
        }
    }

      定义动态代理类,注意一定要实现接口 InvocationHandler

    public class DynamicProxy implements InvocationHandler{
    
        /**这个就是要代理的委托对象,使用Object类型,可以代理不同类型的对象,便于复用*/
        private Object source;
    
        /**构造器,给要代理的对象赋值*/
        public DynamicProxy(Object source) {
            this.source = source;
        }
    
        /*
        我的理解:当我们通过动态代理对象调用委托对象的方法时会执行该方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            /*当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用*/
            method.invoke(source,args);
            after();
            return null;
        }
    
        void before(){
            System.out.println("调用对象方法前执行的业务逻辑");
        }
    
        void after(){
            System.out.println("调用对象方法后执行的业务逻辑");
        }
    }

      测试类

    public class Test {
        public static void main(String[] args) {
            //要代理的真实对象
            Source realSource = new SourceImpl();
            //创建handler实例,我们要代理哪个对象就把该对象传进去,最后通过该真是对象来调用其方法
            InvocationHandler handler = new DynamicProxy(realSource);
            /**
             * 通过Proxy.newProxyInstance方法来创建代理对象,
             * 第一个参数是目标对象的类加载器,获取方法为geiClassLoader()
             * 第二个参数是一个Interface对象的数组,表示的是将要给需要代理的对象提供一组什么借口,
             *     如果我提供了一组接口给它,那么这个代理对象就可以实现该接口(多态),
             *     这样就能调用这组接口中的方法了
             *     这里我们为代理对象提供的接口是真实对象所实行的接口,表示要代理的是该真是对象,
             *     这样就可以调用这组接口中的方法了
             * 第三个参数handler,指定的动态代理处理器,将该动态处理器传入真实的代理对象,即委托类对象
             */
            Source source = (Source) Proxy.newProxyInstance(Source.class.getClassLoader(),
                    realSource.getClass().getInterfaces(),handler);
            source.describe();
            System.out.println("");
            source.buyHourse();
        }
    }

      输出结果

    调用对象方法前执行的业务逻辑
    中國風
    调用对象方法后执行的业务逻辑
    
    调用对象方法前执行的业务逻辑
    购房
    调用对象方法后执行的业务逻辑

      OK,至此两个常见的代理模式就到这里了,明天说一下使用第三方插件实现的CGLIB代理模式;下班了回家!!祝大家中秋节快乐!!!

    持续更新中...

    参考链接: https://www.cnblogs.com/daniels/p/8242592.html

          https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

      

  • 相关阅读:
    移位运算符
    java 链表数据结构
    log4j.properties配置详解
    java异常面试题
    QuickHit项目(输出字符串游戏)
    适配器模式
    java 单例
    sql索引的填充因子多少最好,填充因子的作用?
    聚焦索引和非聚焦索引的区别
    二叉树。。。。
  • 原文地址:https://www.cnblogs.com/yueguanguanyun/p/9687886.html
Copyright © 2011-2022 走看看