美文网首页
代理模式

代理模式

作者: 小院里栽棵树 | 来源:发表于2022-04-27 15:22 被阅读0次

再聊代理模式前,我们先看下什么场景下我们会需要用到代理模式,以及为什么要用?

举个我们代码中常见的例子:
产品需求:我们需要看到一些指定接口的请求数据,比如请求总耗时时间,上报给服务器,用于了解用户的使用体验。

那我们开始撸代码了

    class LoginRequest {
        fun login() {

            val startTime = System.currentTimeMillis()

            //  ...省略发起登陆请求的代码...

            val endTime = System.currentTimeMillis()

            //上报接口请求的开始时间和结束时间给服务器
            ReportService.report(startTime,endTime,"urlLogin")
        }
    }


    class HomePageRequest {
        fun homePageData() {

            val startTime = System.currentTimeMillis()

            //  ...省略发起首页数据请求的代码...

            val endTime = System.currentTimeMillis()

            //上报接口请求的开始时间和结束时间给服务器
            ReportService.report(startTime,endTime,"urlHomePage")
        }
    }

很明显,上面的写法有2个问题,
1:请求耗时的代码和上报日志的代码完全重复,我们需要在每一个上报的请求中都重复此代码.
2:获取请求耗时的代码和上报的代码,和请求的代码在业务上毫无关联,耦合太高.

为了将上报框架代码和请求业务代码解耦,代理模式就派上用场了!

简单说下什么是代理模式:代理模式的本质就是在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。了解了代理模式的本质,我们再写改造一下上面的例子也加深理解。

    interface ILoginInterface{
        fun login()
    }

    class LoginRequest : ILoginInterface{
        override fun login() {
            //  ...省略发起登陆请求的代码...
        }
    }
    
    class LoginRequestProxy(private val realLogin:LoginRequest):ILoginInterface{
        override fun login() {
            val startTime = System.currentTimeMillis()

            realLogin.login()

            val endTime = System.currentTimeMillis()

            //上报接口请求的开始时间和结束时间给服务器
            ReportService.report(startTime,endTime,"urlLogin")
        }
    }

通过代码我们可以发现,LoginRequest类中只有登陆请求的业务代码了,获取请求耗时和上报的代码都被我们放置在了LoginRequestProxy中了,这样我们就做到了上报框架代码和业务代码的解耦。这种写法就是静态代理.

但上面的写法也有个问题在于:我们需要给每个需要解耦、需要被代理的类都去创建一个xxxProxy代理的类,这个工作不仅繁琐,同时还增加了维护成本,后续只要我们新增一个接口请求,都要创建一个代理类,实现相同的接口。这听着都让人头大~ 那有没有一劳永逸的办法呢,让我们不用每次都创建一个新的代理类?那就是我们下面要说到的动态代理了.

动态代理:就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。那如何实现动态代理呢?
在java中使用是很方便的,系统已经给我们提供了Api,下面就让我们看下如何使用吧。

    interface IRequestInterface {
        fun request(url: String)
    }

    class LoginRequest : IRequestInterface {
        override fun request(url: String) {
             //  ...省略发起登陆请求的代码...
        }
    }

    
    //创建代理类的handler
    class InvokeHandler(private val instance: IRequestInterface, val url: String) : InvocationHandler {
    
        private var startTime by Delegates.notNull<Long>()
        private var endTime by Delegates.notNull<Long>()
    
        override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? {

            if (method.name.equals("request")) {
                startTime = System.currentTimeMillis()
            }
    
            //这里需要注意 invoke接收的是可变参数,这里不可以直接传递args,要变成可变参数
            val result = method.invoke(instance, *(args ?: emptyArray()))
    
            when (method.name) {
                "request" -> {
                    endTime = System.currentTimeMillis()
                    report(startTime, endTime, url) 
                }
            }
    
            return result
        }
    
        private fun report(startTime: Long, endTime: Long, url:String) {
            ReportService.report(startTime,endTime,url)
        }
    }

    //使用代码
    class Test {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val proxy = createProxy(LoginRequest(),"urlLogin")
            proxy.request("urlLogin")
        }

        private fun createProxy(instance: IRequestInterface,url: String): IRequestInterface {
            val classLoader = instance::class.java.classLoader
            val interfaces = instance::class.java.interfaces
            val invokeHandler = InvokeHandler(instance,url)
            return Proxy.newProxyInstance(
                classLoader,
                interfaces,
                invokeHandler
            ) as IRequestInterface
        }
    }
}

我们可以发现,我们把请求耗时、上报的功能都放到了InvokeHandler类的invoke方法中去处理,后续如果我们新增接口,也只需通过Proxy.newProxyInstance动态创建一个代理类就可以了,而无需我们在项目中手动创建xxxProxy类了

相关文章

  • 设计模式

    单例模式 模板方法模式 工厂模式 代理模式 静态代理 JDK动态代理

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • kube-proxy的3种模式

    userspace代理模式 iptables代理模式 IPVS代理模式 https://kubernetes.io...

  • 第4章 结构型模式-代理模式

    一、代理模式简介 二、代理模式3个角色 三、代理模式的优点 四、代理模式的实例(游戏代练)

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 结构型 代理模式(文末有项目连接)

    1:什么是代理模式 2:没用代理模式时的实例 3:使用代理模式将其解耦(静态代理) 3:使用代理模式将其解耦(动态...

  • 设计模式-动态代理模式

    之前介绍了代理模式,大家也都了解了代理模式,不过之前介绍的代理模式是静态代理,静态代理什么意思?静态代理指的是代理...

  • 代理模式

    一、什么是代理模式 代理模式(Proxy pattern):代理模式又叫委托模式,是为某个对象提供一个代理对象,并...

  • 设计模式之代理模式(Proxy模式)

    代理模式的引入 代理模式的实例程序 代理模式的分析 代理模式的引入 Proxy是代理人的意思,指的是代替别人进行工...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

网友评论

      本文标题:代理模式

      本文链接:https://www.haomeiwen.com/subject/kdmkmktx.html