kotlin扩展与内联函数帮助实现接口隔离原则

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

前言

什么是接口隔离原则?不强迫开发者实现不想使用的方法。Java的做法就是建立单一接口,不要建立内容量庞大的接口,尽量细分接口,同时接口中的方法也要尽量少。换句话说,为每个类建立专用的接口,而不要建立一个很多内容的接口供所有依赖它的类去调用。

示例

相信大家都用过TextWatcher这个接口类,当我们在等待TextView发生改变的时候需要使用此接口,而且开发过程使用频率极高,在开发中被广泛使用。假设我们需要在用户输入字符的时候显示一个toast提示,为此我们一般都需要通过addTextChangedListener来实现TextWatcher接口,但是我们又必须被迫的实现TextWatcher的3个回调。

代码如下所示:

et_info.addTextChangedListener(object: TextWatcher {
    override fun beforeTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int){
        // 文本改变前
    }
    override fun onTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int) {
        Toast.makeText(this, charSequence.toString, Toast.LENGTH_LONG).show()
    }
    override fun afterTextChanged(charSequence: Editable?) {
        // 文本改变前
    }
})

但实际上,我们只需要使用onTextChanged这一个回调来实现我们的Toast功能。我们不需要使用beforeTextChangedafterTextChanged函数,那么这样写就违反了接口隔离原则。

那么现在问题就是:我们如何在TextWatcher接口中只使用onTextChanged这一个函数呢?

解决方法

我们可以借助 Kotlin 中的扩展函数和内联函数,来满足我们对接口隔离的需求,首先在EditText类上实现一个扩展函数,将需要被执行的函数以lambda的形式传递到TextWatcheronTextChanged这一函数内执行。

代码如下所示:

inline fun EditText.onTextChange(crossinline invoke: (String) -> Unit) {
    this.addTextChangedListener(object: TextWatcher {
        override fun beforeTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int){
        // 文本改变前
        }
        override fun onTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int){
            // 执行外部逻辑
            invoke(charSequence.toString())
        }
        override fun afterTextChanged(charSequence: Editable?) {
        // 文本改变前
        }
    })
}

在这里,我们将一个 lambda 函数invoke作为参数添加到我们的 onTextChange 扩展函数。函数invokeString 作为参数。每当调用 TextWatcher 中的回调函数 onTextChanged 时,我们将调用函数invoke并将字符串参数传递给它。外部 EditText 在使用的时候就会比较便捷。

代码如下所示:

et_info.onTextChange{
    Toast.makeText(this, it, Toast.LENGTH_LONG).show()
}

代码分析

  • inline:内联函数的使用增强了高阶函数的性能。内联函数告诉编译器将参数和函数复制到调用站点。

  • crossinline:crossinline修饰符以避免非本地返回。如果我们在 lambdas 中添加了返回,它将允许非本地返回并将代码留在其下方。为了避免这种情况,我们在 lambda 函数invoke之前使用 crossinline 修饰符。

总结

当我们尝试实现包含大量功能的接口,并且只需要使用其中极个别的回调函数时,我们可以采用这种方式来提高我们代码的简洁性与高效性。

猜你喜欢

转载自juejin.im/post/7110222090825334815