zoukankan      html  css  js  c++  java
  • 设计模式-代理模式

    代理模式

    代理模式是常用的设计模式,他的特征是代理类与委托类具有相同的接口,代理类主要为委托类预处理消息、过滤信息、把消息转发给委托类、以及事后处理消息等。代理类与委类一般会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类对象本身并不提供服务,而是通过调用委托类对象相关的方法来提供服务。

      按照代码的创建时期,代理类可分为两种:

      a)静态代理:通过代码工具或手写生成源代码,再对其编译。在程序运行前,代理类相关.class就已经存在;

      b)动态代理:在程序运行时,通过反射机制动态创建而成;

     

      静态代理:

      静态代理其实就是按照代理模式,实现了代理类与委托类之间的调用方式,可以看作是代理模式的写法;

      代理模式有三个角色:

    • 抽象代理角色:声明了目标对象与代理对象的共同接口,这样可以在任何可以使用目标对象的地方都可以使用代理对象。
    • 目标对象角色:定义了代理对象所对表的目标对象。
    • 代理对象角色:代理对象的内部含有目标对象的引用,从而可以在任何时候使用目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。  

      源代码 

      

    /***
     * 抽象对象
     */
    interface AbstractObject {
        fun request()
    }
    /**
     * 委托类(目标类)
     * */
    class RealObject :AbstractObject {
    
        override fun request() {
            println("http request")
        }
    }
    /**
     * 代理类
     * */
    class ProxyObject : AbstractObject {
    
      //委托类 private var realObject: RealObject? = null constructor(realObject_: RealObject) { this.realObject = realObject_ } override fun request() { println("调用目标对象之前的一些操作") realObject?.request() println("调用目标对象之后的一些操作") } }

    调用:

    class Main {
        companion object {
            @JvmStatic
            fun main(args: Array<String>) {
                val realObject = RealObject()
                val proxyObject = ProxyObject(realObject)
                proxyObject.request()
            }
        }
    }

    结果:

    调用目标对象之前的一些操作
    http request
    调用目标对象之后的一些操作

    动态代理: 

    动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。

    代理类和委托类的关系是在程序运行时确定。

    通俗来说:比如登录之前需要判断用户信息是否完整、请求之前需要配置请求数据等等,动态代理就是来处理这样的需求,让用户只需要关心事件处理。

    我们先看看与动态代理紧密关联的java api:

    • java.lang.reflect.Proxy

      动态代理的加载器;

    • java.lang.reflect.InvocationHandler

      动态代理类处理方法主要是依赖InvocationHandler接口;

    • java.lang.ClassLoader

    Proxy的代码:

    //ClassLoader, 指被代理的对象
    //Class[] interfaces,要调用的方法
    //InvocationHandler h,方法调用时所需的参数
    public
    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... }

    该类的newProxyInstance()方法需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,java中有以下三种类加载器:

    • Booststrap ClassLoader,此加载器采用C++编写,一般开发中是看不到的;
    • Extendsion ClassLoader,用来进行扩展类的加载,一般以应jrelibext目录中的类;
    • AppClassLoader,(default)加截classpath指定的类,是最常使用的一种加载器;

    InvocationHandler的代码:

    //Object proxy,指被代理的代象
    //Method method,要调用的方法
    //Object[] args,方法调用时所需的参数
    public
    interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

    invoke方法是动态处理类的主要方法;

    动态代理的实现步骤

    • 实现InvocationHandler接口创建自已的调用处理口
    • 给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类
    • 以调用处理器类型为参数,利用反射机制得到动态代理类的构造函数
    • 以调用处理器对象为参数,利用动态代理类的构造函数创建动态代理类对象

    源代码

    class HttpRequestJDKProxy : InvocationHandler {
    
        private var target: Any? = null
    
        fun bind(target_: Any):Any? {
            this.target = target_
            //取得代理对象
            return Proxy.newProxyInstance(
                target!!::class.java.classLoader,
                target!!::class.java.interfaces,
                this
            )
        }
    
        override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
            println("调用目标对象之前的一些操作")
            //利用反射机制将请求分派给委托类处理。
            //Method的invoke返回Object对象作为方法执行结果。
         val result = method?.invoke(target, *(args ?: arrayOfNulls<Any>(0)))
            println("调用目标对象之后的一些操作")
            return result
        }
    }

    笔者用kotlin语言来编写例子遇到了以下的问题:

    反射api中Method的invoke方法中第二个参数接收可变长参数,在java中允许数组赋值给可变长参数Object... args,Kotlin中,数组是array,可变长参数类型是vararg,类型不一致,运行时会报错,所以在kotlin中,可以使用*符号放在args前面,把它变成可变长参数。参考

    运行

    val jdkProxy = HttpRequestJDKProxy()
    val realObject = RealObject()
    val dynamicProxyObject = jdkProxy.bind(realObject) as AbstractObject
    dynamicProxyObject.request()

    结果跟静态代理的一样。

  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/johnnyzhao/p/10400747.html
Copyright © 2011-2022 走看看