一、前言
代理模式有利于针对某些场景进行解耦。通常有两种实现方式,静态代理和动态代理,这里对其进行记录。除了解耦外,还有一个好处就是让程序结构更加清晰理解
二、静态代理
假设有这么一个场景,我们找房子,通常找房东的话会有很多流程,但是找中介的话只要告诉需求就行了。中介会给我们最终的结果,中介自己把其余繁琐流程进行处理。虽然在现实中找中介也会很麻烦。简要代码如下:
class Subject {
fun call(){
println("---->找到房子")
}
}
class Proxy(private val subject: Subject) {
fun call(){
println("-->开始找房,联系房东")
subject.call()
println("-->找房结束,进行后续维护")
}
}
class ExampleUnitTest {
@Test
fun proxyTest(){
val subject = Subject()
val proxy = Proxy(subject)
proxy.call()
}
}
执行结果如下:
-->开始找房,联系房东
---->找到房子
-->找房结束,进行后续维护
我们这里看下如果我们不使用代理模式的话会怎么写。代码如下:
class ExampleUnitTest {
@Test
fun proxyTest(){
val subject = Subject()
println("-->开始找房,联系房东")
subject.call()
println("-->找房结束,进行后续维护")
}
}
可以看到这个代码把一些不必要的细节暴漏了出来,虽然可以写个管理类啥的进行二次封装。但是还是没有分割开,不利于重用。这些代码少的话还好,要是多的话就会看起来很凌乱。
三、动态代理
上文记录了静态代理。不过静态代理有个问题,如果有很多个需要进行代理的话,就要写很多个代理类,比如我找房子,找了链家、我爱我家、我爱我屋啥的。这样的话在实际开发上就会很费劲,总不能每次产生一个新的东西,都要写一个代理类吧。虽然也可以写个管理类,类似于中介的中介,一个大管家管理所有中介。不过这个不在这次讨论范围。
这里对上述的代理模式进行改动,由于动态代理需要使用接口(动态代理会生成新的类,所以也只能是接口),所以修改如下:
interface Subject {
fun call()
}
class SubjectIml: Subject {
override fun call() {
println("---->找到房子")
}
}
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
class ProxyFactory(private val target: Any) {
//给目标对象生成代理对象
fun getProxyInstance(): Any? {
return Proxy.newProxyInstance(
target.javaClass.classLoader,
target.javaClass.interfaces,
object : InvocationHandler {
@Throws(Throwable::class)
override operator fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
println("-->开始找房,联系房东")
//执行目标对象方法
val returnValue: Any? = method.invoke(target, *(args ?: emptyArray()) )
//*(args ?: emptyArray()) 这句代码的*是伸展操作符,将一个数组展开程可变数组。由因为这个数组不可为null,所以需要使用?: 进行判断。
println("-->找房结束,进行后续维护")
return returnValue //需要注意的是这里返回什么都行,所以在Retrofit里面返回了自己定义的新的对象,而这个对象和传入的对象没有关系
// return null
// return 1
// return ""
}
}
)
}
}
class ExampleUnitTest {
@Test
fun proxyFactory(){
val subject = SubjectIml()
val proxy: Subject = ProxyFactory(subject).getProxyInstance() as Subject
println("-->"+proxy.javaClass)
proxy.call()
}
}
四、仿写Retrofit的动态代理
Retrofit的动态代理和这个略有不同,因为Retrofit只有接口,所有具体实现类均由动态代理实现所以代码修改如下:
interface Subject {
fun call()
}
class ProxyFactory {
//给目标对象生成代理对象
fun <T> getProxyInstance(service: Class<T>): Any? {
return Proxy.newProxyInstance(
service.classLoader,
arrayOf(service),
object : InvocationHandler {
@Throws(Throwable::class)
override operator fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
println("-->开始找房,联系房东")
//执行目标对象方法
// If the method is a method from Object then defer to normal invocation.
if (method.declaringClass == Any::class.java) {
return method.invoke(this, *(args ?: emptyArray()))
}
println("-->找房结束,进行后续维护")
// return null
// return 1
return ""
}
}
)
}
}
class ExampleUnitTest {
@Test
fun proxyFactory(){
val proxy: Subject = ProxyFactory().getProxyInstance(Subject::class.java) as Subject
println("-->"+proxy.javaClass)
proxy.call()
}
}
需要注意的是因为没有执行自己实现的具体类,所以当初写的那个具体类的代码将不会执行,其结果如下:
-->class com.sun.proxy.$Proxy14
-->开始找房,联系房东
-->找房结束,进行后续维护