委托模式已经被证明是实现继承的一个很好的替代方式,在扩展一个基类并且重写方法时,基类就必须依赖子类的实现,当不断地修改的时候,基类就会失去当初的性质,Kotlin中就将类默认为final
,确保不会被修改。
有一种模式是装饰器模式,本质就是创建一个新类,实现与基类一样的接口,并且将类的实现作为一个字段保存,这样就能在基类不被修改就能直接修改基类的实例。但是这样的缺点是会造成很多的样板代码。
class DelegatingCollection<T> : Collection<T> {
private val innerList = mutableListOf<T>()
override val size: Int
get() = innerList.size
override fun contains(element: T): Boolean = innerList.contains(element)
override fun containsAll(elements: Collection<T>): Boolean = innerList.addAll(elements)
override fun isEmpty(): Boolean = innerList.isEmpty()
override fun iterator(): Iterator<T> = innerList.iterator()
}
当你实现Collection
接口的时候,需要重写这几个方法,这里面的代码量是很多的,但是如果用了委托,那么代码就是这样的
class DelegatingCollection2<T>(innerList: Collection<T> = mutableListOf<T>()) : Collection<T> by innerList
这么简单?就能实现那几个方法?我们来看一下生成的代码
是不是省去了很多手写的代码量,下面我们来介绍这种属性。
委托模式(Delegate)
Kotlin支持委托模式,是允许对象组合实现与继承相同的代码复用的,简单来说就是操作的对象不用自己去执行,而是将任务交给另一个对象操作,这样的模式就叫委托模式,被操作的对象叫委托。
委托模式是有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
类委托
同样我们用上面集合的栗子,现在我们已经是委托到一个对象了,如果我们要修改集合里面的方法的时候,可以直接重写,而不用重复的去写新的方法,下面我们来在一个集合里面插入数据,并且获取插入的次数。
下面代码是默认实现MutableCollection
接口,获取插入的次数
class DefaultCollection<T> : MutableCollection<T> {
private val innerList = mutableListOf<T>()
private var addedSum = 0
override fun add(element: T): Boolean {
addedSum++
return innerList.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
addedSum += elements.size
return innerList.addAll(elements)
}
override val size: Int
get() = innerList.size
override fun contains(element: T): Boolean = innerList.contains(element)
override fun containsAll(elements: Collection<T>): Boolean = innerList.addAll(elements)
override fun isEmpty(): Boolean = innerList.isEmpty()
override fun iterator(): MutableIterator<T> = innerList.iterator()
override fun clear() = innerList.clear()
override fun remove(element: T): Boolean = innerList.remove(element)
override fun removeAll(elements: Collection<T>): Boolean = innerList.removeAll(elements)
override fun retainAll(elements: Collection<T>): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
实现类委托
class DelegatingCollection3<T>(private val innerList: MutableCollection<T> = HashSet<T>()) : MutableCollection<T> by innerList {
private var addedSum = 0
override fun add(element: T): Boolean {
addedSum++
return innerList.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
addedSum += elements.size
return innerList.addAll(elements)
}
}
是不是省去很多无用的代码,只需要重写我们需要的方法add
和addAll
,其他没有写出来的方法全部都交给委托来实现。
而且没有对底层集合的实现方法引入任何的依赖,所以对被调用的操作具有完全的控制,如不用担心集合是不是通过循环中调用add
来实现addAll
。
委托属性(Delegate Properties)
有一种属性,在使用的时候每次都要手动实现它,但是可以做到只实现一次,并且放到库中,一直使用,这种属性称为委托属性。
委托属性包括:
- 延迟属性(lazy properties):数据只在第一次被访问的时候计算。
- 可观察属性(observable properties):监听得到属性变化通知。
Map
委托属性(Storing Properties in a Map):将所有属性存在Map
中。
class Foo {
var p: String by Delegate()
}
委托模式的语法是val/var <property name>: <Type> by <expression>
在by
后面的expression
就是委托的部分,会将属性的get()
和set()
委托给getValue()
和setValue()
方法。
class Foo {
private val delegate = Delegate()
var p: String
set(value: String) = delegate.setValue(..