Android设计模式详解之代理模式

前言

代理模式也称为委托模式,是一种结构型设计模式;

定义:为其他对象提供一种代理以控制对这个对象的访问;

使用场景:无法或不想直接访问某个对象访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口;

UML类图:
Android设计模式详解之代理模式_第1张图片

  • Subject:抽象主题类,该类的主要职责是申明真实主题与代理的共同接口方法,该类即可以是一个抽象类也可以是一个接口;
  • RealSubject:真实主题类,该类也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑方法,而客户类则通过代理类间接地调用真实主题类中定义的方法;
  • ProxySubject:代理类,该类也称为委托类或代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中响应的接口方法执行,以此起到代理的作用;
  • Client:客户端类,使用代理类;

静态代理

定义:代理类在编译阶段生成,在程序运行之前就已经存在的代理模式,称为静态代理;

这里我们以租客租房为例,租客租房一般会找对应的租房中介,租房中介负责租房,同样,办理退房的时候也交给中介去处理即可;

示例代码

  • 定义租房抽象主题接口,IRental
/**
 * 租房,抽象主题角色
 */
interface IRental {
    /**
     * 租房
     */
    fun renting()

    /**
     * 退租
     */
    fun rentingOut()
}
  • 定义租客类,Tenant
/**
 * 租客,真实主题类
 */
class Tenant(private val name: String) : IRental {
    override fun renting() {
        println("$name 办理租房手续")
    }

    override fun rentingOut() {
        println("$name 办理退房手续")
    }
}
  • 定义租房中介,RentalProxy
/**
 * 租房中介,代理类
 */
class RentalProxy(private val rental: IRental) : IRental {
    override fun renting() {
        rental.renting()
    }

    override fun rentingOut() {
        rental.rentingOut()
    }
}
  • 编写测试类验证
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //定义租客
        val tenant = Tenant("Alice")
        //租房中介
        val rentalProxy = RentalProxy(tenant)
        rentalProxy.renting()
        println("------------------")
        rentalProxy.rentingOut()
    }
}

输出结果:

Alice 办理租房手续
------------------
Alice 办理退房手续

优点:
静态代理对客户端隐藏了被代理类接口的具体实现类,在一定程度上实现了解耦合,同时提高了安全性;

缺点:

  • 静态代理类需要实现被代理类的接口,并实现其方法,造成了代码的大量冗余;
  • 静态代理只能对某个固定接口的实现类进行代理服务,其灵活性不强;

动态代理

由于静态代理所存在的问题,才有了动态代理

定义:在程序运行期,创建目标对象的代理对象,对目标对象中的方法进行功能性增强的一种技术。

也就是说代理类是在程序运行时才产生的;

在java中使用Proxy类的newProxyInstance()方法去创建一个代理类的实例对象;

示例代码

我们还是以租客租房为例,这里通过动态代理来实现;

  • 定义租房抽象主题接口,IRental
/**
 * 租房,抽象主题角色
 */
interface IRental {
    /**
     * 租房
     */
    fun renting()

    /**
     * 退租
     */
    fun rentingOut()
}
  • 定义租客类,Tenant
/**
 * 租客,真实主题类
 */
class Tenant(private val name: String) : IRental {
    override fun renting() {
        println("$name 办理租房手续")
    }

    override fun rentingOut() {
        println("$name 办理退房手续")
    }
}
  • 实现InvocationHandler接口TenantInvocationHandler
class TenantInvocationHandler(private val tenant: IRental) : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        return method?.invoke(tenant) //当调用被代理对象的方法时,都在统一到这里执行
    }
}
  • 使用动态代理实现租房退房
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //定义租客
        val tenant = Tenant("Alice")
        //使用动态代理
        val proxy = Proxy.newProxyInstance(
            tenant::class.java.classLoader,
            arrayOf(IRental::class.java),
            TenantInvocationHandler(tenant)
        ) as IRental
        proxy.renting()
        println("----------------------")
        proxy.rentingOut()
    }
}

结果输出:

Alice 办理租房手续
----------------------
Alice 办理退房手续

优点:

  • 可以在不改变方法源码的情况下,实现对方法功能的增强,提高代码复用性。
  • 非常灵活,支持任意接口类型的实现类对象做代理,也可以直接接本身做代理;

如果小伙伴对动态代理的实现原理感兴趣,可以移步:Android动态代理源码分析

Android源码中的代理模式

  • Binder进程间通信原理,通过AIDL实现进程间通信,都会生成代理类,最终客户端通过代理类调用远程服务的方法;
  • Retrofit的实现,高明的动态代理模式使用,这里不再赘述,感兴趣的小伙伴可以参考:Retrofit原理解析

总结

代理模式基本没有什么缺点可言,尤其是动态代理,在Android开发中运用十分广泛,值得我们深入学习;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

你可能感兴趣的:(玩转设计模式,android,设计模式,代理模式)