想象一下,委托就像是生活中的"代办"情景:
1. 属性委托 (Property Delegation)
🏠 场景一:租房管理
class Tenant {
// 把房租交给房产中介来管理
var rent: Int by RentAgent(1000)
}
class RentAgent(private var value: Int) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
println("房客查询房租")
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: Int) {
println("房客通过中介调整房租")
value = newValue
}
}
2. 常见的内置委托
2.1 lazy - 懒汉式加载
就像点外卖🍜:
class Restaurant {
// 只有在第一次访问时才会真正去做这道菜
val specialDish by lazy {
println("开始准备特色菜...")
"宫保鸡丁"
}
}
fun main() {
val restaurant = Restaurant()
// 第一次访问,会打印"开始准备特色菜..."
println(restaurant.specialDish)
// 第二次访问直接返回已经做好的菜
println(restaurant.specialDish)
}
2.2 observable - 观察者模式
像是给孩子零花钱💰:
class PocketMoney {
var amount: Int by Delegates.observable(0) { _, old, new ->
println("零花钱从 $old 变成了 $new")
if (new > old) {
println("孩子很开心!")
} else {
println("孩子有点失落...")
}
}
}
2.3 vetoable - 带验证的观察者
像是家长监管孩子玩游戏🎮:
class GameTime {
var minutes: Int by Delegates.vetoable(0) { _, _, new ->
when {
new > 120 -> {
println("今天玩太久了,不允许!")
false
}
new < 0 -> {
println("时间不能为负数!")
false
}
else -> true
}
}
}
3. 类委托 (Class Delegation)
想象一个团队协作场景👥:
interface Worker {
fun work()
fun report()
}
// 实际工作者
class JuniorDeveloper : Worker {
override fun work() = println("写代码,修Bug...")
override fun report() = println("完成了一个小功能")
}
// 项目经理通过委托管理初级开发
class ProjectManager(private val developer: Worker) : Worker by developer {
override fun report() {
println("先整理一下报告格式...")
developer.report()
println("加上一些专业术语...")
}
}
4. 委托的实际应用场景
4.1 单例模式实现
object DatabaseConfig by lazy {
loadConfigFromFile()
}
4.2 ViewModel 中的状态管理
class MyViewModel : ViewModel() {
private var _uiState by mutableStateOf(UiState())
val uiState: UiState by _uiState
}
4.3 SharedPreferences 封装
class UserSettings(context: Context) {
private val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var username by SharedPreferencesDelegate(prefs, "")
var isLoggedIn by SharedPreferencesDelegate(prefs, false)
}
5. 常见问题及解决方案
5.1 内存泄漏问题
❌ 错误示范:
class MyActivity : AppCompatActivity() {
// 可能导致内存泄漏
private val heavyObject by lazy { HeavyObject(this) }
}
✅ 正确做法:
class MyActivity : AppCompatActivity() {
// 使用 lifecycleScope 管理
private val heavyObject by lazy { HeavyObject(lifecycleScope) }
}
5.2 线程安全问题
// 需要线程安全时使用 Delegates.synchronized
var sharedState by Delegates.synchronized(初始值)
5.3 性能问题
当使用大量委托时:
// 不推荐
class DataModel {
val field1 by lazy { compute1() }
val field2 by lazy { compute2() }
val field3 by lazy { compute3() }
// ... 更多委托
}
// 推荐
class DataModel {
private val initializer by lazy {
ComputeResult(
compute1(),
compute2(),
compute3()
)
}
val field1 get() = initializer.result1
val field2 get() = initializer.result2
val field3 get() = initializer.result3
}
6. 最佳实践建议
-
🎯 明确目的:只在真正需要委托模式的地方使用它
-
📝 文档化:为自定义委托属性添加清晰的文档
-
🔍 可测试性:确保委托类的行为可以被单元测试覆盖
-
🛠 保持简单:不要过度使用委托,导致代码难以理解
-
💡 性能考虑:在性能敏感的场景下,评估委托带来的开销
通过这些生动的例子和实践建议,相信您对 Kotlin 的委托机制已经有了更深入的理解。委托机制不仅让代码更加优雅,还能帮助我们更好地实现各种设计模式和功能需求。记住,委托就像现实生活中的"代办",合理使用可以让代码更加清晰和可维护。