zoukankan      html  css  js  c++  java
  • 公用技术——设计模式12——结构型模式——代理模式

    1、概念

      代理模式将调用类方法的操作转换为调用代理类的方法,这样做的目的是:

    1. 实现了”按需调用”,它和延迟加载类的思想是一致的。以此达到性能的提升。
    2. 调用代理类方法时,可以在原功能之前添加一些功能,之后加入一些功能。例如记录类方法的执行时间。

      第一种情况下,代理模式的本质是延迟原方法的调用时间,实现”按需调用”。此时原方法具备的特点是比较耗时,代理模式的目的是提升性能。

      第二种情况下,代理模式的本质是拦截原方法,在其之前添加一些功能性代码,在其之后添加一些功能性代码。它与面向切面的思想是一致的,spring的AOP功能就是通过代理模式实现的。

      它的解决方案是:

      提供额外的代理类,第一种情况时,代理类的职责是执行耗时的功能。第二种情况时,代理类的职责是抽象公共,通用,而且较为重要的功能,这些功能包括日志,安全监测等等。

      它的实现方式有两种,静态代理和动态代理,区别在于代理类的创建时机,类之间的关系,代理类方法触发原类方法的方式。

    2、UML图

    2.1   静态代理

      2.2  动态代理(JDK方式)

        

    3、代码

    3.1   静态代理

      接口,它扮演着被代理的角色

    /**
     * @File Name: RealInterface.java 
     * @Description: 接口类
     * @version 1.0
     * @since JDK 1.8
     */
    public interface RealInterface {
    	/**
    	 * 
    	 * @Title: work
    	 * @Description:实现某个特定的功能
    	 */
    	void work();
    }
    

      接口实现类

    /**
     * @File Name: RealInterfaceImpl.java 
     * @Description: 接口实现类
     * @version 1.0
     * @since JDK 1.8
     */
    public class RealInterfaceImpl implements RealInterface {
    
    	@Override
    	public void work() {
    	}
    }
    

      代理类,扮演着代理的角色。它与被代理的接口是实现,组合的关系。

    /**
     * @File Name: ProxyObject.java 
     * @Description: 代理类
     * @version 1.0
     * @since JDK 1.8
     */
    public class ProxyObject implements RealInterface {
    	// 被代理的接口类
    	private RealInterface realInterface;
    	
    	@Override
    	public void work() {
    		realInterface.work();
    	}
    }

    3.2   动态代理

      MyInvocationHandler,它实现InvocationHandler接口,只有一个方法invoke,它的核心作用是触发原方法的调用。它相当于静态代理方式中ProxyObject中的work方法。

    /**
     * 
     * @File Name: MyInvocationHandler.java 
     * @Description: InvocationHandler接口实现类
     * @version 1.0
     * @since JDK 1.8
     */
    public class MyInvocationHandler  implements InvocationHandler{
    	
    	private RealInterface real = new RealInterfaceImpl();
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		return method.invoke(real, args);
    	}
    }
    

      原接口RealInterface,与静态代理方式的代码相同,此处略。

      动态生成的代理类Proxy$0,如果想查看该类,需要设置sun.misc.ProxyGenerator.saveGeneratedFiles变量为true。它是一个JVM系统变量。

    public final class $Proxy0 extends Proxy implements RealInterface {
    	private static Method m1;
    	// m3代表被代理接口中的方法,其他变量代表equals,hashCode等
    	private static Method m3;
    	private static Method m2;
    	private static Method m0;
    
    	public $Proxy0(InvocationHandler var1) throws  {
          super(var1);
       }
        // 略
    	public final boolean equals(Object var1);
        /**
         * 创建与原接口的同名方法,
         * 它与InvocationHandler的关系是构造器依赖关系
         * 它与代理Interface产生相同的方法
         * InvocationHandler与被代理的Interface之间关系为set依赖关系,与被代理方法Method,Proxy对象是方法参数依赖关系
         */
    	public final void work() throws  {
          try {
             super.h.invoke(this, m3, (Object[])null);
          } catch (RuntimeException | Error var2) {
             throw var2;
          } catch (Throwable var3) {
             throw new UndeclaredThrowableException(var3);
          }
       }
    
        // 略
    	public final String toString();
        // 略
    	public final int hashCode();
    
    	static {
    		try {
    			m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
    			m3 = Class.forName("designpattern.proxy.RealInterface").getMethod("work");
    			m2 = Class.forName("java.lang.Object").getMethod("toString");
    			m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    		} catch (NoSuchMethodException var2) {
    			throw new NoSuchMethodError(var2.getMessage());
    		} catch (ClassNotFoundException var3) {
    			throw new NoClassDefFoundError(var3.getMessage());
    		}
    	}
    }  

    4、讨论

    1.   问题1:代理模式的主要功能?

      答:代理模式的主要功能是将原方法的调用转换为代理方法的调用。代理方法与原方法的关系在第一种情况下是”按需调用”,第二种情况下是增强原方法的功能。这些功能通常都是公共的,并且是较为重要的。

      2.   问题2:代理模式的实现方式有哪些,以及它们的区别?

      答:代理模式有两种,静态代理和动态代理,动态代理目前有两种技术,一种是JDK,另一种是CGLib。

      静态代理和动态代理在本质上没有区别,都是代理方法替换原方法,并在代理方法中触发原方法的调用。

           二者的区别在于代理类的创建方式和代理类之间的关系上。

    • 静态代理的代理类是由我们手动创建的,而动态代理是由JVM动态产生的。
    • 静态代理的代理类和被代理接口之间的关系是实现,依赖的关系。而在动态代理时,代理类与被代理接口之间的关系还是实现关系,代理类依赖原方法对应的Metthod对象。触发原方法的方式也变为super.h.invoke方法,将Method对象作为该方法的参数,在其内部调用Method对象的invoke方法。

      3.   问题3:代理模式类之间的关系?

      答:静态代理,ProxyObject与RealObject实现相同的接口,并且依赖RealObject。代理类触发原方法的方式是通过RealObject对象的实例去调用。

      动态代理,Proxy与XXInterface之间的关系为实现关系,静态代理的依赖关系转变为Proxy与Method之间的依赖关系。Proxy与InvocationHandler是依赖关系,是通过构造器的方式注入的。InvocationHandler与XXInterface之间的关系为依赖关系,是通过Set的方式注入的。

      抛开复杂的类关系,掌握代理方法与原方法之间的关系会更容易理解代理模式。

      代理类是提供代理方法的,总是有触发原发法的实现机制,不论是通过组合被代理接口的实现类,还是组合原方法的Method对象。

    5、示例

    1. Spring框架中作用域为singleton的bean依赖作用域为prototype的bean时。想达到每次获取依赖bean都是不同实例时。
    2. Spring框架中AOP的实现。
  • 相关阅读:
    authentication与网站安全验证
    Android 不一样的原生分享
    iOS学习笔记——AutoLayout的约束
    积累一下SQL
    关于数据链接底层
    减少生成的dll数量
    iOS学习笔记——使用ChildViewController
    iOS学习笔记——键盘处理
    iOS学习笔记——触控与手势
    iOS学习笔记——多控制器管理
  • 原文地址:https://www.cnblogs.com/rain144576/p/9940889.html
Copyright © 2011-2022 走看看