kotlin类委托、属性委托
1.类委托
(1)概念
本类需要实现的方法/属性,借用其他已实现该方法/属性的对象作为自己的实现;
一旦使用了某类作为委托类,该类就能借用该委托类实现的方法/属性。
(2)定义
/**
* 定义一个生物接口,有一个run抽象方法和一个抽象属性
*/
interface Creature {
fun run()
val type: String
}
/**
* 定义一个委托类,实现了Creature接口
*/
class DelegateClass : Creature {
override val type: String
get() = "委托类该属性"
override fun run() {
println("代理类执行run方法")
}
}
①委托类作为构造器形参传入(常用)
/**
* 定义一个Human类,实现了Creature接口,委托类作为形参传入,由形参委托类对象作为委托对象
*/
class Human(delegateClass: DelegateClass) : Creature by delegateClass
②新建委托类对象
/**
* 定义一个Dog类,实现了Creature接口,新建一个委托类作为委托对象
*/
class Dog : Creature by DelegateClass()
③新建委托类对象,并自己实现方法/属性
/**
* 定义一个pig类,实现了Creature接口,新建一个委托类作为委托对象,并自己实现了抽象方法
*/
class Pig : Creature by DelegateClass() {
override fun run() {
println("自己执行实现的run方法")
}
override val type: String
get() = "自己实现的type属性"
}
调用示例:
fun main(args: Array<String>) {
//作为形参(委托对象可复用)
val delegateClass = DelegateClass()
val human = Human(delegateClass)
human.run()//结果:代理类执行run方法
println(human.type)//结果:委托类该属性
val human2 = Human(delegateClass)
human2.run()//结果:代理类执行run方法
println(human2.type)//结果:委托类该属性
//新建对象
val dog = Dog()
dog.run()//结果:代理类执行run方法
println(dog.type)//结果:委托类该属性
//新建对象并自己实现方法/属性
val pig = Pig()
pig.run()//结果:自己执行实现的run方法
println(pig.type)//结果:自己实现的type属性
}
2.属性委托
(1)概念
多个类的类似属性交给委托类统一实现,避免每个类都要单独重复实现一次。
(2)定义
/**
* 定义一个委托类Jobs,
* 为属性name创建了operator修饰的getValue和setValue方法
* 该属性可被其他了委托该类共享
*/
class Jobs {
var name: String = "工作名"
operator fun setValue(thisRef: SoftWareDev, property: KProperty<*>, value: String) {
this.name = value
}
operator fun getValue(thisRef: SoftWareDev, property: KProperty<*>): String {
return this.name
}
}
/**
* 定义一个接口
*/
interface SoftWareDev
/**
* 定义一个AndroidDev类,实现SoftWareDev接口
* 属性name委托Jobs类实现
*/
class AndroidDev : SoftWareDev {
var name: String by Jobs()
}
/**
* 定义一个PhpDev类,实现了SoftWareDev接口
* 属性name委托Jobs类实现
*/
class PhpDev : SoftWareDev {
var name: String by Jobs()
}
/**
* 定义一个类实现了SoftWareDev接口
*/
class ExtensionClass : SoftWareDev
/**
* 为ExtensionClass扩展属性,该属性由委托类Jobs实现
*/
val ExtensionClass.name by Jobs()
fun main(args: Array<String>) {
val androidDev = AndroidDev()
androidDev.name = "android开发"
println(androidDev.name)//结果:android开发
val phpDev = PhpDev()
println(phpDev.name)//结果:工作名
println(ExtensionClass().name)//结果:工作名
}
(3)关于委托类的委托属性的getValue、setValue形参说明
①getValue(thisRef, property)
-
thisRef:代表委托属性所属对象,因此thisDef类型需要与委托属性所属对象类型一致,或者是其父类,如上面代码thisRef类型为SoftWareDev,是AndroidDev和PhpDev两个类的父类类型;
-
property:代表目标属性,该属性必须是KProperty<*>类型或其父类类型;
-
返回值:返回目标属性相同的类型,或者其子类类型。
②setValue(thisRef, property, value)
-
thisRef:同上;
-
property:同上;
-
value:为目标属性设置的新的值,因此该值类型必须与目标属性类型一致,或者是其父类。
总结:传入形参类型需与目标类型一致或者是其父类类型,返回值类型需与目标类型一致或者是其子类类型。
(4)关于ReadOnlyProperty和ReadWriteProperty接口
- ReadOnlyProperty接口定义了getValue方法;
- ReadWriteProperty接口定义了getValue、setValue方法。
因此,委托类可以实现ReadOnlyProperty(val声明待委托属性时)或者ReadWriteProperty(var声明待委托属性时)接口来进行委托属性的定义。
上面Jobs类完全可以这么实现:
/**
* 定义一个委托类Jobs,
* 实现了ReadWriteProperty接口,重写setValue、getValue方法
* 该属性可被其他了委托该类共享
*/
class Jobs : ReadWriteProperty<SoftWareDev,String>{
var name: String = "工作名"
override operator fun setValue(thisRef: SoftWareDev, property: KProperty<*>, value: String) {
this.name = value
}
override operator fun getValue(thisRef: SoftWareDev, property: KProperty<*>): String {
return this.name
}
}