zoukankan      html  css  js  c++  java
  • 【设计模式】结构型01代理模式(Proxy Pattern)

    代理模式(Proxy Pattern)


    定义:顾名思义,增加中间层,为其他对象提供一种代理以控制对这个对象的访问。核心在于代理二字。

    1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

    2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

    静态代理与动态代理:

    静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
    动态代理类:在程序运行时,运用反射机制动态创建而成。
    静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
    静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。

    动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。

    代码:静态代理:

    这里笔者通过一个替考的例子,演示了小学生王小虎找人替考被骗子骗的故事:

    package com.pat.proxy.staticproxy;
    /**
     * 统一接口
     * @author ZX
     *
     */
    public interface Student {
    	void exam();
    }
    /**
     * 被代理类-学生王小虎
     * @author ZX
     *
     */
    class BadStudent implements Student{
    	private String name="王小虎";
    
    	@Override
    	public void exam() {
    		System.out.println(name+"参加考试");
    		
    	}
    	public BadStudent(){
    	}
    	public BadStudent(String name){
    		this.name=name;
    	}
    }
    /**
     * 代理类-替考的骗子
     * 静态代理只代理固定的类
     * @author ZX
     *
     */
    class Swindler implements Student{
    	private String name;
    	private BadStudent badStudent;
    	
    	@Override
    	public void exam() {
    		//非重点,前后可以添加某些操作
    		System.out.println(name+"进入考场");
    		badStudent= new BadStudent(name);
    		badStudent.exam();
    		System.out.println(name+"没交试卷");
    		
    	}
    	public Swindler(String name){
    		this.name=name;
    	}
    }

    测试类:

    package com.pat.proxy.staticproxy;
    
    public class Test {
    	public static void main(String[] args) {
    		Student s = new Swindler("老司机");
    		s.exam();
    	}
    }
    

    结果:

    老司机进入考场
    老司机参加考试
    老司机没交试卷
    这就说明了一个问题,做生意得讲诚信,你好好搞替考业务,发展起来说不定还能开个连锁。这样子做生意是不会走的长远的!但是考虑到这个替考人没上过小学,也只能怪小虎人品不好了。

    代码:动态代理:

    以下是动态代理的演示,采用了JDK提供的工具,省了几十行代码:

    package com.pat.proxy;
    /**
     * 本类中
     */
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * 被代理类接口
     */
    public interface People {
        public int getNum() ;
    }
    
    /**
     * 被代理类实现类
     */
    class Peopleimpl implements People{
         private int num=100;
    
        public int getNum() {
            return num;
        }
    
        public void setNum(int num) {
            this.num = num;
        }
    }
    /**
     *代理类,需要实现InvocationHandler接口
     */
    class MyInv implements InvocationHandler{
        //被代理对象
        Object obj;
    
        public  MyInv(Object obj){
            this.obj=obj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(obj, args);
            return result;
        }
    }

    测试类:

    package com.pat.proxy;
    
    import java.lang.reflect.Proxy;
    import java.util.Objects;
    
    /**
     * 测试类:
     * 补充,非空判断这么用比较装逼:
     * People p2=null;
     * Objects.requireNonNull(p2,"第二个对象不能为空");
     */
    public class Test2 {
        public static void main(String[] args) {
            //动态代理有JDK和CGLIB两种工具,cglib是更底层的写法,所以效率会高一些
            People p = new Peopleimpl();
            //真正的代理者。
            MyInv my = new MyInv(p);
            //第一个参数是类加载器,第二个参数是这个代理者实现哪些接口(与被代理者实现的是相同的接口)
            People pp= (People)Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(),my);
            System.out.println(pp.getNum());
    
    
    
    
        }
    }
    

    结果:

    100

    动态代理JDK中的实现:

    每日手记:
    2018年5月15日11:16:07
    Returns an instance of a proxy class for the specified interfaces
    返回一个指定接口的代理实例
    that dispatches method invocations to the specified invocation
    handler.
    将方法调用分派到指定的处理程序
    
    
        /**
         //糊上注释是为了看一下老外是怎么写注释的,即使看不懂全部,也可以对比自己的注释参考一下,其实注释写得多也给人感觉很牛逼
         * Returns an instance of a proxy class for the specified interfaces
         * that dispatches method invocations to the specified invocation
         * handler.
         *
         * <p>{@code Proxy.newProxyInstance} throws
         * {@code IllegalArgumentException} for the same reasons that
         * {@code Proxy.getProxyClass} does.
         *
         * @param   loader the class loader to define the proxy class
         * @param   interfaces the list of interfaces for the proxy class
         *          to implement
         * @param   h the invocation handler to dispatch method invocations to
         * @return  a proxy instance with the specified invocation handler of a
         *          proxy class that is defined by the specified class loader
         *          and that implements the specified interfaces
         * @throws  IllegalArgumentException if any of the restrictions on the
         *          parameters that may be passed to {@code getProxyClass}
         *          are violated
         * @throws  SecurityException if a security manager, <em>s</em>, is present
         *          and any of the following conditions is met:
         *          <ul>
         *          <li> the given {@code loader} is {@code null} and
         *               the caller's class loader is not {@code null} and the
         *               invocation of {@link SecurityManager#checkPermission
         *               s.checkPermission} with
         *               {@code RuntimePermission("getClassLoader")} permission
         *               denies access;</li>
         *          <li> for each proxy interface, {@code intf},
         *               the caller's class loader is not the same as or an
         *               ancestor of the class loader for {@code intf} and
         *               invocation of {@link SecurityManager#checkPackageAccess
         *               s.checkPackageAccess()} denies access to {@code intf};</li>
         *          <li> any of the given proxy interfaces is non-public and the
         *               caller class is not in the same {@linkplain Package runtime package}
         *               as the non-public interface and the invocation of
         *               {@link SecurityManager#checkPermission s.checkPermission} with
         *               {@code ReflectPermission("newProxyInPackage.{package name}")}
         *               permission denies access.</li>
         *          </ul>
         * @throws  NullPointerException if the {@code interfaces} array
         *          argument or any of its elements are {@code null}, or
         *          if the invocation handler, {@code h}, is
         *          {@code null}
         */
        @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
            //克隆了接口参数
            final Class<?>[] intfs = interfaces.clone();
            //安全管理器,有关权限以及安全的东西,无视之
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    	//下面就是通过反射创建动态代理对象的过程了:
    				
            /*
             * Look up or generate the designated proxy class.查找或生成指定的代理类。           
               //如果由给定的加载器定义的代理类。
               //给定的接口存在,这将简单地返回缓存的副本(这个缓存取自哪里?猜想:类加载???);
               //否则,它将通过ProxyClassFactory创建代理类。
    	         //如果没有接口参数intfs,则会抛出空指针
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    	    //获取构造方法
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {//非公有方法处理
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                //返回创建的代理对象
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }

  • 相关阅读:
    HDU 6071
    HDU 6073
    HDU 2124 Repair the Wall(贪心)
    HDU 2037 今年暑假不AC(贪心)
    HDU 1257 最少拦截系统(贪心)
    HDU 1789 Doing Homework again(贪心)
    HDU 1009 FatMouse' Trade(贪心)
    HDU 2216 Game III(BFS)
    HDU 1509 Windows Message Queue(队列)
    HDU 1081 To The Max(动态规划)
  • 原文地址:https://www.cnblogs.com/the-fool/p/11054141.html
Copyright © 2011-2022 走看看