Android代理模式中的那些代码

题记

为什么突然会想到整理下代理模式?emm…因为最近头脑风暴了下自己的知识体系,还是对自己代码架构上的东西不够满意。最近梳理的很多知识体系中,反复都提到了代理模式。

  1. 比如Hook这个玩意真的是令我又爱又恨,其中对动态代理的渗透,让我对这个代码的设计欲罢不能。给篇参考链接:Android插件化原理解析——Hook机制之动态代理
  2. 再比如Binder通信,Android 中的AIDL对代理模式的使用也是精彩绝伦。

1. 为什么叫代理模式

官方解释:一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
不扯皮解释:加个中介。比如说:我想吃个外卖,我没必要亲自去那家店订餐,我只需要去第三方平台订就可以了,平台里面有那家店的订餐方式,都提供了订餐这个方法,可以帮我去那家店订餐。注意,这里最后做饭的操作仍然是那家实体店,平台只是帮我传递一下消息。
好处? 被代理类的方法属性被保护起来了,我不用修改有关被代理类的代码,直接在代理类中添加一系列的逻辑操作。这不就是开闭原则么?不上一段冠冕堂皇的解释:1、职责清晰。 2、高扩展性。 3、智能化。
概念混淆。这个东西跟装饰者模式很像,但是装饰者主要是装饰 → 添加更多功能,而代理模式的重点是控制 → 开闭原则。

2. 静态代理

文字总结起来甚是困难,不如几行代码来的舒心。这里仍然已订餐为例子(PS:我今晚真的不会再订宵夜了,我已经胖到起飞了。)

  1. 明确自己需要做的动作(买吃的),创建一个包含待实现动作的接口。
	interface BuyFood {
    	fun buyFood()
	}
  1. 一个实际操作对象(被代理)需要实现这个操作(接口)。
class Shop constructor(var name: String) : BuyFood {
    init {
        println("Shop:$name")
    }

    override fun buy() {
        println("Shop:买买买")
    }
}
  • 代理类如果要代理这个操作,不需要用户直接操作被代理的对象,则必须要持有这个对象并且实现相同的方法。
class ProxyPlatform constructor(var name: String) : BuyFood {
    var shop: Shop? = null;

    override fun buy() {
        println("我是XX代理平台")
        if (shop == null) {
            shop = Shop(name)
        }
        shop!!.buy()
        println("点好了")

    }
}
  • 测试。
class TestPro {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            ProxyPlatform("鸡米花").buy()
        }
    }
    
}

在这里插入图片描述

3. 动态代理

看了上面的代码,其实感觉有点像小孩子过家家。总不能我每实现一个接口就写一个代理类把?就想到能不能偷懒?一个代理类完成所有功能。这时候就体现出前人的肩膀是多么的稳固。JDK中这些东西其实都是直接封装好的了,我们直接用好了。注意俩个关键支持:
接口java.lang.reflect.InvocationHandler
java.lang.reflect.Proxy

3.1 InvocationHandler

//...
public interface InvocationHandler {
 //...
 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

点到源码里面看,注释的定义给的一清二楚,简单摘取点有用信息。
类注释

  • 代理实例需要实现这个接口
  • 代理实例调用方法触发invoke(...)
  • JDK1.3开始和入这个类。

方法注释:invoke(...)

  • Object proxy被代理对象
  • Method method待调用的方法
  • Object[] args方法调用时入参

3.1 Proxy

Proxy的源码太长了,这里就不粘贴了。

  • 它提供创建动态代理的静态方法类和实例,它也是所有由这些方法创建的动态代理的父类。
  • 注意newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)看到第一个参数的类加载器,基本就可以确定这里也是用到的反射加载。

其实我这里都是废话,仔仔细细读一遍其中的注释就好了。

4. 代码

接口和其实现类一样的,没啥变化。

interface BuyFood {
    fun buy()
}

class Shop constructor(var name: String) : BuyFood {
    override fun buy() {
        println("Shop:买买买")
    }
}

继承InvocationHandler接口的代理平台。这里我们直接传入了被代理的对象,直接扔到invoke方法里面。

class ProxyHandler constructor(var any: Any) : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        var methodName=method?.name;
        if (methodName.equals("buy")) {
            println("我是XX动态代理平台")
            println("需要传递$methodName()接口")
            val result = method!!.invoke(any, *args.orEmpty())
            println("点好了")
            return result
        }
        return null;
    }
}

测试类进行调用。这里有个坑,newProxyInstance(...),第一个参数传入真实被代理类的加载器,第二个参数一定要传入待实现的接口类,不能传入已经实现的真实被代理类。

class TestPro {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val shop:Shop= Shop("鸡米花")
            //第二个参数注意是待实现接口类数组类型
            val  proxy=Proxy.newProxyInstance(shop.javaClass.classLoader, arrayOf(BuyFood::class.java),ProxyHandler(shop))as BuyFood
            proxy.buy()
        }
    }

好处显而易见了,这个代理平台根据传入的不同类型,做出不同的动作,可以减少很多代码量。当然,invoke()里面也要加入很多逻辑判断。比如到底传递哪个待实现接口?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值