Kotlin语法糖 Part3
前言
在前面的两篇文章中,我们了解到了:
- sealed
- when()
- with()
- inline function and reified type
在这章中,我会给大家分享我是如何使用Kotlin委托机制的。
Kotlin的委托机制
Kotlin有一个内置的委托模式。在一些书中也提及委托模式是实现继承的一个很好的替代方式,在Kotlin使用它进行聚合非常容易:
interface Navigable {
val onNavigationClick: (()->Unit)?
}
interface Searchable {
val searchText:String
}
class Component(navigation: Navigable, searchable: Searchable): Navigable by navigable, Searchabe by searchable
使用by关键字,即可委托navigation、searchable的所有行为。比起Java,Kotlin减少了大量的模板代码。如果你把interface标记为internal,你会发现编译不能通过
‘public’ function exposes its ‘internal’ parameter type xxx
Kotlin编译器不允许暴露模块的内部组件,如果想在不暴露Navigable,Searchable的前提下解决这个问题,你只需要做:
- 移除构造器
- 使用组合代替聚合
- 定义包含Navigable和Searchable方法名的ComponentInterface
interface ComponentInterface {
val onNavigationClick: (()->Unit)?
var searchText: String
}
class Component: ComponentInterface {
private val navigable: Navigable = NavigableImpl()
private val searchable: Searchable = SearchableImpl()
override val onNavigationClick: (()->Unit)?
get() = navigable.onNavigationClick
override var searchText: String = ""
get() = searchable.searchText
set(value) {
field = value
searchable.searchText = value
}
}
经过改造后,你发现代码从零模板的聚合变成了看上去很讨厌的组合方式。但是先别哭,Kotlin总能给你带来愉悦的编码体验。Kotlin不仅支持使用by关键字对指定对象进行方法委派,还具有委托属性的机制。你可能已经在使用lazy关键字初始化对象时接触到了它的这一机制了。
private val lazyProperty by lazy { "" }
怎么从使用lazy()上来改造上面组合的代码呢,请看代码:
class ReferencedProperty<T>(private val get: () -> T,
private val set: (T) -> Unit = {}) {
operator fun getValue(thisRef: Any?,
property: KProperty<*>): T = get()
operator fun setValue(thisRef: Any?,
property: KProperty<*>,
value: T) = set(value)
}
fun <T> ref(property: KMutableProperty0<T>) = ReferencedProperty(property::get,
property::set)
fun <T> ref(property: KProperty0<T>) = ReferencedProperty(property::get)
ReferencedProperty用两个方法作为参数,并定义了两个函数:
- get函数返回泛型T
- set函数以T作为参数
- getValue()调用get()
- setValue()调用set()
最重要的一点是你需要知道操作符用到了属性代理机制。在ReferencedProperty类下,你会发现两个返回ReferencedProperty的泛型方法,第一个用于var,第二个用于val。
现在让我们用ref()简化代码
class Component : ComponentInterface {
private val navigable: Navigable = NavigableImpl()
private val searchable: Searchable = SearchableImpl()
override val onNavigationClick by ref(navigable::onNavigationClick)
override var searchText by ref(searchable::searchText)
}
希望看完这三章你能有些许收获。
参考
6 magic sugars that can make your Kotlin codebase happier — Part 3