在 Kotlin 中,属性委托和类委托是两种通过 by
关键字实现的强大特性,它们通过“委托”机制将行为或实现逻辑委托给其他对象,从而实现代码的复用和解耦。
1 属性委托
定义: 允许把属性的 get
和 set
方法的具体实现委托给另一个对象。
语法:
var/val 属性名: 类型 by 委托对象
委托类的要求:
- 对于
val
(只读属性),需要实现getValue()
; - 对于
var
(可变属性),需要实现getValue()
和setValue()
常见的使用场景:
- 延迟初始化:
by lazy
(首次访问时才进行初始化); - 属性监听:
Delegates.observable
(属性值发生变化时触发回调); - 动态属性存储:从
Map
中读取属性(如解析 JSON 或配置);
示例:
class Person(val name: String, val age: Int)
val person: Person by lazy {
Person("Eileen", 34)
}
var name: String by Delegates.observable("init data") { prop, old, new ->
println("${prop.name} 从 $old 变为 $new")
}
class Student(val map: Map<String, Any>) {
val name: String by map // 从 map 中按 key 取值
val age: Int by map
}
val student = Student(mapOf("name" to "Eileen", "age" to 30))
println(student.name) // Eileen
Kotlin 标准库提供的委托工具:
lazy
:延迟初始化;Delegates.observable
:监听属性变化;Delegates.vetoable
:在赋值前校验值是否合法;Delegates.notNull
:非空属性的延迟赋值;
2 类委托
定义:将类的接口实现委托给另一个对象,实现组合复用。 通过组合代替继承,避免单继承的局限性。
语法:
class 类名(委托对象): 接口 by 委托对象
典型场景:
- 装饰器模式:增强对现有对象的功能(如添加日志、缓存);
- 接口实现复用:多个类共享同一接口的默认逻辑;
- 动态替换行为:运行时切换委托对象(如策略模式);
示例:
interface DataFetcher {
fun fetchData(): String
}
class NetworkFetcher : DataFetcher {
override fun fetchData() = "从网络获取数据"
}
// 通过委托添加缓存功能
class CachedFetcher(private val fetcher: DataFetcher) : DataFetcher by fetcher {
private var cachedData: String? = null
override fun fetchData(): String {
return cachedData ?: fetcher.fetchData().also { cachedData = it }
}
}
fun main() {
val networkFetcher = NetworkFetcher()
val cachedFetcher = CachedFetcher(networkFetcher)
println(cachedFetcher.fetchData()) // 第一次调用从网络获取
println(cachedFetcher.fetchData()) // 第二次直接返回缓存
}