zoukankan      html  css  js  c++  java
  • java23种设计模式-结构型模式-代理模式

    一、定义

    为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

     代理模式分为静态代理、动态代理。动态代理又分为JDK动态代理和CGLIB动态代理。

    二、优点及缺点

    静态代理优点:

    1、客户端不必知道实现类(委托类)的内部方法实现,只需要调用代理类即可。

    缺点:

    1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。但这样出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也要实现这个方法。这显然增加了代码的复杂度。

    2、代理对象只服务于一种类型的对象,如果要服务多类型的对象,那就要对每种对象都进行代理,程序过于繁琐。

    动态代理优点:

    1、减少编程的工作量:无需为每个方法都写一个代理方法,无需为每一个类都书写一个代理类。

    2、系统扩展性和维护性增强,修改方便,直接修改代理类。

    三、代码实现:

    1、静态代理

    接口类:

    package com.example.demo.sjms.jingtaidailimoshi;
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 18:10:25
     *  @Description: 买车接口
     */
    public interface ByCar {
    public void payForTheCar(int money);
    }

    实现类:

    package com.example.demo.sjms.jingtaidailimoshi;
    
    import lombok.Data;
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 18:10:57
     *  @Description: 买车的实现类
     */
    @Data
    public class Customer implements ByCar{
        private int money;
        @Override
        public void payForTheCar(int money) {
            System.out.println("使用"+money+"元,买了一辆车");
        }
    }

    代理类:

    package com.example.demo.sjms.jingtaidailimoshi;
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:23
     *  @Description: 代理类,需要在调用买车方法之前,首先判断这个人的钱是否够用
     */
    public class CarProxy implements ByCar {
        // 最少钱数
        private final int MIN_MONEY = 100000;
        // 引入委托对象
        private Customer customer;
        public CarProxy(Customer customer){
            this.customer = customer;
        }
        // 代理方法
        @Override
        public void payForTheCar(int money) {
            if(customer.getMoney() < MIN_MONEY){
                System.out.println("钱数不够无法购买,还缺"+ (MIN_MONEY - money)+"元");
                return;
            }
            customer.payForTheCar(money);
        }
    
    }

    测试类:

    package com.example.demo.sjms.jingtaidailimoshi;
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:33
     *  @Description: 测试类
     */
    public class Test {
        public static void main(String[] args) {
            CarProxy carProxy = new CarProxy(new Customer());
            carProxy.payForTheCar(1000);
        }
    }

    2、动态代理

    (1)、JDK动态代理(基于实现相同的接口)

    JDK动态代理是基于反射机制。通过java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。最主要的特点就是,代理类必须和被代理类实现相同的接口,也就是说被代理类一定要有实现的接口,否则不可以使用JDK动态代理。

    实体类和接口类不再多写和上面相同

    动态代理类:

    package com.example.demo.sjms.JDKdongtaidaili;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:15
     *  @Description: JDK动态代理
     */
    public class JDKProxy<T>{
        private T target;
        public JDKProxy(T target){
            this.target = target;
        }
        /***
         *  @Author: caesar
         *  @Date:2020年10月15日 19:10:26
         *  @Description: 动态代理方法
         *  @Param:
         *  @Return:
         */
        public T getProxy(){
            return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("方法执行之前执行。。。。。。");
                    Object object = method.invoke(target,args);
                    System.out.println("方法执行之后执行。。。。。。");
                    return object;
                }
            });
        }
    }

    测试类:

    package com.example.demo.sjms.JDKdongtaidaili;
    
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:37
     *  @Description: 测试类
     */
    public class Test {
        public static void main(String[] args) {
            Person user = new User();
            JDKProxy<Person> jdkProxy = new JDKProxy<Person>(user);
            Person proxyUser = jdkProxy.getProxy();
            proxyUser.say();
        }
    }

    (2)、CGLIB动态代理类(继承)

    利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。cglib代理的类,无需强制实现接口,其生成的代理类 是 被代理类的子类,并且重写的被代理类的方法,只需引包即可。

    引入的jar包:

    <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>3.2.12</version>
    </dependency>

    委派类也不再多写,和上面的相同

    CGLIB代理类:

    package com.example.demo.sjms.CGLIBdongtaidaili;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:15
     *  @Description: CGLIB动态代理
     */
    public class CGLIBProxy<T>{
       public T getCGLIBProxy(Class<T> tClass){
           return (T) Enhancer.create(tClass, new MethodInterceptor() {
               @Override
               public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                   System.out.println("方法前执行。。。。。。");
                   Object result = methodProxy.invokeSuper(o, objects);
                   System.out.println("方法后执行。。。。。。");
                   return result;
               }
           });
       }
    }

    测试类:

    package com.example.demo.sjms.CGLIBdongtaidaili;
    
    
    /**
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:37
     *  @Description: 测试类
     */
    public class Test {
        public static void main(String[] args) {
            CGLIBProxy<User> cglibProxy = new CGLIBProxy<User>();
            User proxyUser = cglibProxy.getCGLIBProxy(User.class);
            proxyUser.say();
        }
    }

    四、源码级别

    springAOP就是动态代理:这是本人的有关博客位置:https://www.cnblogs.com/mcjhcnblogs/category/1791152.html

    五、总结

    注释:原来博客中书写过有关代理模式的详解地址如下:可能代码不如这个整洁,但是总结的很详细:https://www.cnblogs.com/mcjhcnblogs/p/13174171.html

  • 相关阅读:
    上百个让你事半功倍的jquery插件
    ashx+jquery+autocomplete.js实现自动填充
    如何引用 System.Runtime.Serialization.Json;
    关于通过标签取得相关文章的算法
    谷歌拼音与搜狗拼音自定义词库互转工具
    Community Sever 2007 简体中文语言包(适用CS2007 RTM/SP1/SP2)
    我的WCF之旅(1):创建一个简单的WCF程序
    网页中嵌入MediaPlayer各种属性与方法设置大全
    我的WCF之旅(3):在WCF中实现双工通信
    SQL Server 2005安装详解
  • 原文地址:https://www.cnblogs.com/mcjhcnblogs/p/13824690.html
Copyright © 2011-2022 走看看