谈谈Java/Kotlin中接口回调

在谈接口回调之前,想什么是接口?在学习类的时候,我们就得知接口主要是用来把某个功能抽象起来,之后,不同的类实现此功能,但其实现的功能不同。

一个生动的例子,把动物的叫这一行为抽象为一个接口,之后不同动物由不同的类代替,这些动物类都实现了这个“叫”接口,但是,他们实现不一样,因为每个动物的叫声都不一样

上面所述为接口的基本定义和功能,接口除了上面的功能外,还可以用来回传数据,也就是所谓的接口回调,即本文谈论的主题

接口回调应用情形

接口回调主要是将数据/状态回传给调用者,举个常见的例子,下载功能

我们定义一个下载的类,此类存在一个download方法,我们只要实例化此类,用对象的调用方式来调用download方法,即可开始下载

问题来了,我们想要得到下载完成这个状态,那么该如何实现呢?

大家可能想到的是一种较为简单的方法,使用返回值来判断当前是否完成,给download方法声明返回值,下载完毕之后返回true

上面的方法可行是可行,但是如果需要得到多个数据呢?如下载完成之后需要返回一个File对象,下载失败则是返回错误信息Exception,按照上面的逻辑的话,你得定义两个类,用来存储数据?然后根据不同的情况返回不同的对象?但是返回值的对象只能是一种类型,你两个类该怎么办?

于是呢,我们可以选择接口回调,可以比较方便的实现上述的问题。

class DownloadUtil { fun download(downloadListener: DownloadListener) { try { //下载操作... //一般下载操作肯定是有个File对象进行读写操作,这里我就省略了 downloadListener.success(file)
        } catch (e: IOException) {
            downloadListener.error(e)
        }
    } interface DownloadListener { fun success(file: File) fun error(e: Exception) }
} 

可以看到,DownloadListener有两个接口方法,success()和error(),当调用者调用的时候,传递了一个接口对象,之后在各自不同的方法就可以处理不同两种情况的逻辑了

val downloadUtil = DownloadUtil()
downloadUtil.download(object :DownloadUtil.DownloadListener{ override fun success(file: File) { //下载成功的相关操作 } override fun error(e: Exception) { //下载失败的相关操作 }

})

Kotlin优雅的接口回调

Kotlin与Java不同的是,如果某个接口有一个方法的话,可以使用Kotlin中的接口参数
这里就谈谈如何使用Kotlin优雅的实现一个接口多方法

上面下载的接口我们是定义了两个方法,一个是下载成功,另外是下载失败,在实现接口的时候,我们必须两个方法都实现,哪怕你不关心某个方法,你都要实现,但方法里面不写任何代码,如果接口方法多的话,简直是地狱

Kotlin的object关键字就是相当于Java中用new来实现接口方法

那么有没有可以自由选择实现某个接口方法的办法呢?当然有,那就是Kotlin中提供的DSL语法

我们把上面的用Kotlin优雅的重构一遍

1.接口构造类

我们需要把接口改造成接口的构造类,如下代码所示

inner class ListenerBuilder {
    internal var successListener: ((file: File) -> Unit)? = null internal var errorListener: ((e: Exception) -> Unit)? = null //这里的方法名之后需要调用 fun onSuccess(action: (file: File) -> Unit) {
        successListener = action
    }

    fun onError(action: (e: Exception) -> Unit) {
        errorListener = action
    }
}

对比: interface DownloadListener {
    fun success(file: File)
    fun error(e: Exception)
}

fun success(file: File) 改造为接口参数((file: File) -> Unit),如果有返回值,把Unit改成对应返回值类型即可

2.提供方法传递接口构造类

private lateinit var mListener: ListenerBuilder

fun download(listener: ListenerBuilder.() -> Unit) {
    mListener = ListenerBuilder().also(listener) try { //下载操作... if (::mListener.isInitialized) {
            mListener.successListener?.invoke(File(""))
        }
    } catch (e: IOException) { if (::mListener.isInitialized) {
            mListener.errorListener?.invoke(e)
        }
    }
}

PS:这里你也可以选择声明另外的方法用于单独设置接口,之后调用逻辑就可以不需要传递接口参数过来,这个看你喜欢吧

3.调用

val downloadUtil = DownloadUtil()
    downloadUtil.download{ //这里onSuccess和onError可选,IDE不会报错 onSuccess { 

        }
        onError { 

        }
    }

下载类源码

class DownloadUtil { private lateinit var mListener: ListenerBuilder

    fun registerListener(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener)
    }
    fun download(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener) try { //下载操作... if (::mListener.isInitialized) {
                mListener.successListener?.invoke(File(""))
            }
        } catch (e: IOException) { if (::mListener.isInitialized) {
                mListener.errorListener?.invoke(e)
            }
        }
    }

    inner class ListenerBuilder {
        internal var successListener: ((file: File) -> Unit)? = null internal var errorListener: ((e: Exception) -> Unit)? = null //这里的方法名之后需要调用 fun onSuccess(action: (file: File) -> Unit) {
            successListener = action
        }

        fun onError(action: (e: Exception) -> Unit) {
            errorListener = action
        }
    }

}
#Java##程序员#
全部评论

相关推荐

专心打鱼:互联网搬运工,贴子都要偷
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务