1. Kotlin委托机制:从继承地狱到组合天堂
作为一名经历过"继承地狱"的开发者,我深刻理解Kotlin委托机制的价值。还记得那个让我重写三遍的电商系统用户体系吗?原本清晰的继承结构随着业务发展变得越来越复杂,最终变成了一团乱麻。正是这段经历让我彻底理解了"组合优于继承"的真谛。
1.1 继承的局限性
让我们先看一个典型的继承问题案例:
kotlin复制open class BaseUser {
open fun login() { }
open fun logout() { }
}
open class PremiumUser : BaseUser() {
override fun login() { /* 增强登录 */ }
open fun accessPremiumFeatures() { }
}
class VIPUser : PremiumUser() {
override fun login() { /* VIP登录 */ }
override fun accessPremiumFeatures() { /* VIP特权 */ }
fun getDiscount() { }
}
// 新需求:临时会员(需要登录增强,但不是Premium)
class TemporaryUser : BaseUser() { // 无法复用PremiumUser的login
override fun login() {
// 只能复制粘贴PremiumUser的login代码
}
}
这个案例暴露了继承的几个核心问题:
- 代码重复:无法复用PremiumUser的登录逻辑,只能复制粘贴
- 灵活性差:继承关系在编译时确定,无法运行时调整
- 耦合度高:父类修改会影响所有子类
- 单继承限制:无法同时继承多个类的功能
1.2 委托模式的救赎
委托模式完美解决了这些问题。看看用委托重构后的代码:
kotlin复制interface LoginBehavior {
fun login()
}
class EnhancedLogin : LoginBehavior {
override fun login() {
println("增强登录逻辑")
}
}
class TemporaryUser(
loginBehavior: LoginBehavior
) : LoginBehavior by loginBehavior // 关键委托语法
val tempUser = TemporaryUser(EnhancedLogin())
tempUser.login() // 调用EnhancedLogin的实现
重构后的优势显而易见:
- 代码复用:直接复用EnhancedLogin的实现
- 灵活性:运行时可以更换不同的登录行为
- 低耦合:通过接口交互,不依赖具体实现
- 多组合:可以组合多个不同行为
提示:Kotlin的
by关键字是委托模式的语法糖,编译器会自动生成转发方法,避免了Java中需要手动实现每个方法的繁琐。
2. 类委托深度解析
2.1 基本语法与原理
Kotlin的类委托通过by关键字实现,基本语法如下:
kotlin复制interface Printer {
fun print(message: String)
fun getStatus(): String
}
class ConsolePrinter : Printer {
override fun print(message: String) {
println("Console: $message")
}
override fun getStatus(): String = "Console Printer Ready"
}
class LoggingPrinter(
private val printer: Printer
) : Printer by printer { // 委托所有方法给printer
// 可以选择性覆盖某些方法
override fun print(message: String) {
println("[LOG] Printing...")
printer.print(message) // 调用被委托对象的方法
}
}
编译器实际上会生成类似下面的代码:
kotlin复制class LoggingPrinter(private val printer: Printer) : Printer {
override fun print(message: String) {
println("[LOG] Printing...")
printer.print(message)
}
// 编译器自动生成
override fun getStatus(): String {
return printer.getStatus()
}
}
2.2 多接口委托
Kotlin支持同时委托多个接口:
kotlin复制interface Clickable {
fun click()
}
interface Focusable {
fun focus()
fun blur()
}
class Button(
clickHandler: Clickable,
focusHandler: Focusable
) : Clickable by clickHandler,
Focusable by focusHandler {
// 类自己的方法
fun render() {
println("Rendering button")
}
}
这种能力使得Kotlin可以轻松实现类似多重继承的效果,同时避免了传统多重继承的复杂性。
2.3 装饰器模式实战
委托是实现装饰器模式的绝佳选择:
kotlin复制interface DataSource {
fun readData(): String
fun writeData(data: String)
}
class FileDataSource(private val filename: String) : DataSource {
override fun readData(): String {
println("Reading from file: $filename")
return "file content"
}
override fun writeData(data: String) {
println("Writing to file: $filename")
}
}
class EncryptionDecorator(
private val dataSource: DataSource
) : DataSource by dataSource {
override fun readData(): String {
val data = dataSource.readData()
return decrypt(data)
}
override fun writeData(data: String) {
val encrypted = encrypt(data)
dataSource.writeData(encrypted)
}
private fun encrypt(data: String) = "encrypted($data)"
private fun decrypt(data: String) = data.removePrefix("encrypted(").removeSuffix(")")
}
装饰器模式的优势在于:
- 运行时组合:可以动态添加功能
- 开闭原则:不修改原有类就能扩展功能
- 灵活组合:可以嵌套多个装饰器
3. 属性委托详解
3.1 属性委托基础
属性委托允许将属性的访问逻辑委托给另一个对象:
kotlin复制class Example {
var property: String by Delegate()
}
class Delegate {
private var storedValue: String = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
storedValue = value
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
编译器会将其转换为:
kotlin复制class Example {
private val property$delegate = Delegate()
var property: String
get() = property$delegate.getValue(this, ::property)
set(value) {
property$delegate.setValue(this, ::property, value)
}
}
3.2 标准委托:lazy
lazy是最常用的属性委托之一,用于延迟初始化:
kotlin复制class HeavyObject {
val expensiveData: String by lazy {
println("Computing expensive data...")
Thread.sleep(1000) // 模拟耗时操作
"Computed Result"
}
}
lazy有三种线程安全模式:
LazyThreadSafetyMode.SYNCHRONIZED(默认):线程安全,但性能略低LazyThreadSafetyMode.PUBLICATION:允许多次初始化,但只使用第一个结果LazyThreadSafetyMode.NONE:非线程安全,性能最高
3.3 标准委托:observable和vetoable
observable允许在属性值变化时收到通知:
kotlin复制class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("${prop.name}: $old -> $new")
}
}
vetoable可以在值变更前进行验证:
kotlin复制class Product {
var price: Double by Delegates.vetoable(0.0) { _, _, newValue ->
newValue >= 0 // 价格不能为负数
}
}
3.4 标准委托:notNull
notNull提供了比lateinit更灵活的延迟初始化:
kotlin复制class Config {
var port: Int by Delegates.notNull()
var host: String by Delegates.notNull()
fun initialize() {
port = 8080
host = "localhost"
}
}
与lateinit相比,notNull的优势在于:
- 支持基本数据类型
- 可以用于局部变量
- 提供更明确的未初始化异常
4. 自定义委托实战
4.1 SharedPreferences委托
Android开发中常用的一种自定义委托:
kotlin复制class PreferenceDelegate<T>(
private val key: String,
private val defaultValue: T
) {
private val prefs: SharedPreferences by lazy {
App.context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return when (defaultValue) {
is String -> prefs.getString(key, defaultValue as String) as T
is Int -> prefs.getInt(key, defaultValue as Int) as T
is Boolean -> prefs.getBoolean(key, defaultValue as Boolean) as T
is Float -> prefs.getFloat(key, defaultValue as Float) as T
is Long -> prefs.getLong(key, defaultValue as Long) as T
else -> throw IllegalArgumentException("Unsupported type")
}
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
prefs.edit().apply {
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
is Long -> putLong(key, value)
else -> throw IllegalArgumentException("Unsupported type")
}
}.apply()
}
}
4.2 带范围验证的委托
kotlin复制class RangeDelegate<T : Comparable<T>>(
private var value: T,
private val range: ClosedRange<T>
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
require(newValue in range) {
"${property.name} must be in range $range, but got $newValue"
}
value = newValue
}
}
// 扩展函数简化使用
fun <T : Comparable<T>> range(initial: T, range: ClosedRange<T>) =
RangeDelegate(initial, range)
class GameCharacter {
var health: Int by range(100, 0..100)
var level: Int by range(1, 1..100)
}
4.3 线程安全委托实现
kotlin复制class SynchronizedDelegate<T>(initialValue: T) {
private var value: T = initialValue
private val lock = Any()
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
synchronized(lock) {
return value
}
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
synchronized(lock) {
value = newValue
}
}
}
5. Map委托与JSON解析
Kotlin标准库支持将Map用作属性存储:
kotlin复制class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
val email: String? by map
}
val user = User(mapOf(
"name" to "Alice",
"age" to 25,
"email" to "alice@example.com"
))
对于可变属性,可以使用MutableMap:
kotlin复制class MutableUser(map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
val map = mutableMapOf<String, Any?>()
val user = MutableUser(map)
user.name = "Bob"
println(map["name"]) // 输出 "Bob"
这种特性在JSON解析时特别有用:
kotlin复制class JsonObject(private val map: Map<String, Any?>) {
val id: String by map
val title: String by map
val completed: Boolean by map
}
val json = """
{
"id": "1",
"title": "Task 1",
"completed": false
}
""".trimIndent()
val obj = JsonObject(Json.parseToMap(json))
6. 委托模式的最佳实践
6.1 何时使用委托
- 需要复用行为但不想继承:当多个类需要共享某些行为,但这些类之间没有"is-a"关系时
- 需要运行时灵活性:当需要在运行时动态改变对象行为时
- 实现装饰器模式:需要在不修改原有类的情况下扩展功能
- 属性访问控制:需要对属性的访问和修改进行特殊处理时
6.2 性能考量
虽然委托会带来轻微的性能开销,但在大多数情况下可以忽略不计:
- 类委托只是多了一次方法调用,JVM会进行内联优化
- 属性委托的getter/setter调用开销在现代设备上几乎可以忽略
- lazy的同步开销只在第一次访问时发生
提示:只有在性能关键路径上才需要考虑委托的开销,其他情况下应优先考虑代码的可维护性和灵活性。
6.3 线程安全建议
- 对于可变委托,确保线程安全
- 使用标准库提供的线程安全委托(如默认的lazy)
- 自定义委托时考虑使用同步机制
- 对于只读委托,通常不需要额外同步
6.4 代码组织技巧
- 为常用委托创建扩展函数:
kotlin复制fun <T> cached(compute: () -> T): Lazy<T> = lazy(compute)
fun <T : Comparable<T>> range(initial: T, range: ClosedRange<T>) =
RangeDelegate(initial, range)
- 将复杂委托提取到单独文件中
- 为自定义委托添加清晰的文档注释
- 考虑创建委托工厂类集中管理常用委托
7. 常见问题与解决方案
7.1 委托与继承的选择
问题:什么时候该用继承,什么时候该用委托?
解答:
-
使用继承当:
- 存在明确的"is-a"关系
- 需要重写父类的protected成员
- 需要与现有框架集成(如Android的Activity继承)
-
使用委托当:
- 只是需要复用某些行为
- 需要运行时灵活性
- 需要组合多个不同来源的行为
- 想要避免脆弱的基类问题
7.2 委托的性能影响
问题:委托会不会显著影响性能?
解答:
- 类委托:几乎无影响,JVM会优化方法调用
- 属性委托:有轻微开销,但在大多数场景下可忽略
- lazy:首次访问有同步开销,后续访问无额外开销
在性能关键路径上,可以考虑:
- 使用非线程安全的lazy模式(LazyThreadSafetyMode.NONE)
- 避免在循环中频繁访问委托属性
- 对于简单属性,直接实现而不使用委托
7.3 委托的调试技巧
问题:如何调试委托属性?
解答:
- 在自定义委托中添加日志:
kotlin复制class LoggingDelegate<T>(private var value: T) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
println("Getting ${property.name} = $value")
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
println("Setting ${property.name} = $value")
this.value = value
}
}
- 使用IDE的调试功能查看委托字段
- 为复杂委托编写单元测试
- 使用Kotlin反射检查委托属性:
kotlin复制val property = obj::property
println("Property ${property.name} is delegated: ${property.isDelegated}")
7.4 委托与框架集成
问题:如何在框架(如Spring、Android)中使用委托?
解答:
- Android中使用委托存储SharedPreferences
- Spring中可以使用委托实现动态代理
- 注意框架的生命周期,避免在委托中持有可能泄漏的资源
- 对于依赖注入的框架,可能需要额外配置:
kotlin复制@Configuration
class DelegatesConfig {
@Bean
fun myDelegate() = MyDelegate()
}
@Component
class MyService(
private val delegate: MyDelegate
) {
var property: String by delegate
}
8. 高级委托模式
8.1 链式委托
委托可以多层嵌套,形成处理链:
kotlin复制interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println(message)
}
}
class TimestampLogger(private val logger: Logger) : Logger by logger {
override fun log(message: String) {
logger.log("[${System.currentTimeMillis()}] $message")
}
}
class PrefixLogger(private val logger: Logger, private val prefix: String) : Logger by logger {
override fun log(message: String) {
logger.log("$prefix: $message")
}
}
// 使用
val logger = PrefixLogger(
TimestampLogger(
ConsoleLogger()
),
"APP"
)
logger.log("Error occurred")
// 输出: APP: [1642384920123] Error occurred
8.2 委托工厂
创建可以生成委托的工厂:
kotlin复制interface DelegateFactory {
fun <T> create(defaultValue: T): ReadWriteProperty<Any?, T>
}
class ThreadSafeDelegateFactory : DelegateFactory {
override fun <T> create(defaultValue: T): ReadWriteProperty<Any?, T> {
return SynchronizedDelegate(defaultValue)
}
}
// 使用
val factory = ThreadSafeDelegateFactory()
class Config {
var setting: String by factory.create("default")
}
8.3 属性委托的组合
可以组合多个属性委托的行为:
kotlin复制class CompositeDelegate<T>(
private var value: T,
private val validators: List<(T) -> Boolean> = emptyList(),
private val onChange: ((T) -> Unit)? = null
) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
override fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
require(validators.all { it(newValue) }) {
"Validation failed for ${property.name}"
}
val oldValue = value
value = newValue
onChange?.invoke(newValue)
}
}
// 使用
class User {
var age: Int by CompositeDelegate(
initialValue = 0,
validators = listOf(
{ it >= 0 },
{ it <= 150 }
),
onChange = { newAge ->
println("Age changed to $newAge")
}
)
}
9. Kotlin委托的设计哲学
Kotlin的委托机制体现了语言的几个核心设计原则:
- 实用性:解决实际开发中的痛点(如装饰器模式的样板代码)
- 类型安全:编译时检查委托契约,避免运行时错误
- 简洁性:用
by关键字隐藏复杂实现细节 - 互操作性:与Java代码良好协作
- 扩展性:允许开发者创建自己的委托实现
这些设计原则使得委托成为Kotlin中强大而灵活的特性,既能解决实际问题,又保持了语言的简洁性和安全性。
10. 实战练习与解决方案
10.1 线程安全的单例委托
kotlin复制class SingletonDelegate<T>(private val initializer: () -> T) {
@Volatile
private var instance: T? = null
private val lock = Any()
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return instance ?: synchronized(lock) {
instance ?: initializer().also { instance = it }
}
}
}
// 使用
class DatabaseManager {
companion object {
val instance: DatabaseManager by SingletonDelegate {
DatabaseManager().apply {
println("Initializing DatabaseManager")
}
}
}
}
10.2 带过期时间的缓存委托
kotlin复制class CachedDelegate<T>(
private val ttlMillis: Long,
private val compute: () -> T
) {
private var lastUpdated = 0L
private var cachedValue: T? = null
private val lock = Any()
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
synchronized(lock) {
val now = System.currentTimeMillis()
return if (cachedValue == null || now - lastUpdated > ttlMillis) {
println("Cache expired, recomputing...")
cachedValue = compute()
lastUpdated = now
cachedValue
} else {
println("Returning cached value")
cachedValue
}
}
}
}
// 使用
class WeatherService {
val currentTemperature: Double? by CachedDelegate(5000) {
fetchTemperatureFromAPI()
}
}
10.3 可撤销修改的委托
kotlin复制class TransactionalDelegate<T>(initialValue: T) {
private var committedValue: T = initialValue
private var workingValue: T = initialValue
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = workingValue
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
workingValue = value
}
fun commit() {
committedValue = workingValue
}
fun rollback() {
workingValue = committedValue
}
fun isDirty(): Boolean = workingValue != committedValue
}
// 使用
class Form {
private val nameDelegate = TransactionalDelegate("")
var name: String by nameDelegate
fun save() {
if (nameDelegate.isDirty()) {
nameDelegate.commit()
println("Name saved")
}
}
fun cancel() {
nameDelegate.rollback()
println("Changes discarded")
}
}
11. Kotlin委托的局限性与替代方案
虽然Kotlin委托非常强大,但也有一些局限性:
- 调试复杂性:委托属性在调试时可能不太直观
- 性能敏感场景:在极端性能要求下可能需要避免
- Java互操作:Java代码无法直接使用Kotlin的委托语法
- 学习曲线:对于新手可能不太容易理解
替代方案包括:
- 手动实现委托模式(如在Java中)
- 使用注解处理器生成代码
- 对于简单场景,直接实现而不使用委托
12. 委托在Android开发中的实际应用
12.1 ViewModel中的懒加载
kotlin复制class UserViewModel : ViewModel() {
private val repository: UserRepository by lazy {
UserRepository()
}
val users: LiveData<List<User>> by lazy {
repository.getUsers()
}
}
12.2 SharedPreferences委托
kotlin复制class AppSettings(context: Context) {
private val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
var darkModeEnabled: Boolean by prefs.boolean(false)
var fontSize: Int by prefs.int(16)
var username: String by prefs.string("")
}
// 扩展函数简化
fun SharedPreferences.boolean(default: Boolean) =
object : ReadWriteProperty<Any?, Boolean> {
override fun getValue(thisRef: Any?, property: KProperty<*>) =
getBoolean(property.name, default)
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) =
edit().putBoolean(property.name, value).apply()
}
12.3 视图绑定委托
kotlin复制class ViewBindingDelegate<VB : ViewBinding>(
private val inflate: (LayoutInflater, ViewGroup?, Boolean) -> VB
) : ReadOnlyProperty<Fragment, VB> {
private var binding: VB? = null
override fun getValue(thisRef: Fragment, property: KProperty<*>): VB {
return binding ?: inflate(
thisRef.layoutInflater,
thisRef.view?.parent as? ViewGroup,
false
).also { binding = it }
}
fun Fragment.viewBinding(inflate: (LayoutInflater, ViewGroup?, Boolean) -> VB) =
ViewBindingDelegate(inflate)
}
// 使用
class MyFragment : Fragment() {
private val binding by viewBinding(MyFragmentBinding::inflate)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
}
13. 委托在后端开发中的应用
13.1 配置属性委托
kotlin复制class AppConfig {
val dbUrl: String by config("DB_URL", "jdbc:default")
val maxConnections: Int by config("MAX_CONNECTIONS", 10)
val debugMode: Boolean by config("DEBUG_MODE", false)
private fun <T> config(envName: String, defaultValue: T): ReadOnlyProperty<Any?, T> {
return object : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return System.getenv(envName)?.let { it as T } ?: defaultValue
}
}
}
}
13.2 缓存委托
kotlin复制class UserService {
private val cache = ConcurrentHashMap<String, User>()
val userLoader: (String) -> User by cached { userId ->
UserRepository.findById(userId)
}
private fun <K, V> cached(loader: (K) -> V): (K) -> V {
return { key ->
cache.getOrPut(key.toString()) { loader(key) } as V
}
}
}
13.3 事务性操作委托
kotlin复制class TransactionalService {
fun <T> transactional(block: () -> T): T {
return TransactionManager.runInTransaction(block)
}
val userUpdater: (User) -> Unit by transactionalOperation()
private fun <T> transactionalOperation(): (T) -> Unit {
return { param ->
transactional {
// 操作逻辑
}
}
}
}
14. 委托与函数式编程的结合
Kotlin委托可以与函数式编程概念结合,创造更强大的抽象:
14.1 高阶函数委托
kotlin复制class FunctionDelegate<T, R>(
private val function: (T) -> R
) : ReadOnlyProperty<Any?, (T) -> R> {
private var memoized: (T) -> R = { arg ->
val result = function(arg)
memoized = { _ -> result } // 后续调用直接返回缓存结果
result
}
override fun getValue(thisRef: Any?, property: KProperty<*>): (T) -> R = memoized
}
// 使用
class MathOperations {
val expensiveCalculation: (Int) -> Int by FunctionDelegate { x ->
Thread.sleep(1000) // 模拟耗时计算
x * x
}
}
14.2 柯里化委托
kotlin复制class CurryingDelegate<T, U, R>(
private val function: (T, U) -> R
) : ReadOnlyProperty<Any?, (T) -> (U) -> R> {
override fun getValue(thisRef: Any?, property: KProperty<*>): (T) -> (U) -> R {
return { t -> { u -> function(t, u) } }
}
}
// 使用
class StringOperations {
val replace: (String) -> (String) -> (String) -> String by CurryingDelegate {
old: String, new: String, str: String ->
str.replace(old, new)
}
}
// 调用方式
val ops = StringOperations()
val replaceComma = ops.replace(",")(";")
val result = replaceComma("a,b,c") // 结果为 "a;b;c"
15. 委托在响应式编程中的应用
15.1 可观察属性与响应式流
kotlin复制class ReactiveModel {
private val _nameChanges = MutableSharedFlow<String>()
val nameChanges: SharedFlow<String> = _nameChanges
var name: String by Delegates.observable("") { _, _, newValue ->
_nameChanges.tryEmit(newValue)
}
}
// 使用
val model = ReactiveModel()
viewModelScope.launch {
model.nameChanges.collect { newName ->
updateUI(newName)
}
}
15.2 属性绑定委托
kotlin复制class BindingDelegate<T>(
private val flow: MutableStateFlow<T>
) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T = flow.value
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
flow.value = value
}
}
// 使用
class UserViewModel {
private val _username = MutableStateFlow("")
val username: String by BindingDelegate(_username)
fun updateUsername(newName: String) {
username = newName // 会自动更新StateFlow
}
}
16. 跨平台开发中的委托应用
Kotlin Multiplatform中委托特别有用:
16.1 平台特定实现委托
kotlin复制expect class PlatformFileSystem {
fun readFile(path: String): String
}
class FileReader {
private val fs: PlatformFileSystem by platformSpecific()
fun readConfig(): String = fs.readFile("config.json")
private inline fun <reified T> platformSpecific(): Lazy<T> = lazy {
when {
Platform.isAndroid() -> AndroidFileSystem() as T
Platform.isJvm() -> JvmFileSystem() as T
Platform.isJs() -> JsFileSystem() as T
else -> throw IllegalStateException("Unsupported platform")
}
}
}
16.2 统一API的多平台委托
kotlin复制interface Database {
fun query(sql: String): ResultSet
}
class DatabaseClient {
val database: Database by lazy {
when {
Platform.isAndroid() -> AndroidDatabase()
Platform.isJvm() -> JdbcDatabase()
else -> throw IllegalStateException("Unsupported platform")
}
}
}
17. 委托与元编程
Kotlin委托可以与反射结合实现更高级的模式:
17.1 动态接口实现
kotlin复制class DynamicDelegate(
private val handler: (String, List<Any?>) -> Any?
) : InvocationHandler {
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
return handler(method.name, args?.toList() ?: emptyList())
}
}
inline fun <reified T : Any> dynamicInterface(
noinline handler: (String, List<Any?>) -> Any?
): T {
return Proxy.newProxyInstance(
T::class.java.classLoader,
arrayOf(T::class.java),
DynamicDelegate(handler)
) as T
}
// 使用
interface UserService {
fun getUser(id: String): User
fun searchUsers(query: String): List<User>
}
val mockService = dynamicInterface<UserService> { method, args ->
when (method) {
"getUser" -> User(args[0] as String, "Mock User")
"searchUsers" -> listOf(User("1", "Alice"), User("2", "Bob"))
else -> throw UnsupportedOperationException(method)
}
}
17.2 属性委托与注解处理
kotlin复制@Target(AnnotationTarget.PROPERTY)
annotation class ConfigValue(val key: String)
class ConfigProcessor {
fun process(config: Any) {
config::class.memberProperties.forEach { prop ->
prop.annotations.filterIsInstance<ConfigValue>().firstOrNull()?.let { ann ->
val value = System.getProperty(ann.key) ?: return@let
if (prop is KMutableProperty<*>) {
when (prop.returnType.classifier) {
String::class -> prop.setter.call(config, value)
Int::class -> prop.setter.call(config, value.toInt())
Boolean::class -> prop.setter.call(config, value.toBoolean())
}
}
}
}
}
}
// 使用
class AppConfig {
@ConfigValue("app.timeout")
var timeout: Int = 0
@ConfigValue("app.debug")
var debugMode: Boolean = false
}
val config = AppConfig()
ConfigProcessor().process(config)
18. 委托的性能优化技巧
18.1 避免委托链过长
kotlin复制// 不推荐:多层嵌套委托
val data by loggingDelegate(
cachingDelegate(
validationDelegate(
rawData
)
)
)
// 推荐:合并委托逻辑
class OptimizedDelegate : ReadWriteProperty<Any?, Data> {
// 合并日志、缓存、验证逻辑
}
18.2 内联简单委托
对于极简单的委托,考虑直接实现:
kotlin复制// 不必要使用委托
var count: Int by Delegates.observable(0) { _, _, _ -> }
// 直接实现可能更高效
private var _count = 0
var count: Int
get() = _count
set(value) {
_count = value
// 变化处理逻辑
}
18.3 缓存反射结果
如果委托使用反射,缓存反射结果:
kotlin复制class ReflectiveDelegate {
private val propertyCache = ConcurrentHashMap<String, KProperty<*>>()
operator fun getValue(thisRef: Any?, property: KProperty<*>): Any? {
val cachedProp = propertyCache.getOrPut(property.name) {
thisRef!!::class.memberProperties.first { it.name == property.name }
}
return cachedProp.getter.call(thisRef)
}
}
19. 委托与协程的结合
19.1 异步初始化委托
kotlin复制class AsyncLazy<T>(
private val scope: CoroutineScope,
private val block: suspend () -> T
) : ReadOnlyProperty<Any?, Deferred<T>> {
private val deferred = scope.async(start = CoroutineStart.LAZY) { block() }
override fun getValue(thisRef: Any?, property: KProperty<*>): Deferred<T> = deferred
}
// 使用
class DataLoader {
private val scope = CoroutineScope(Dispatchers.IO)
val data: Deferred<String> by AsyncLazy(scope) {
fetchDataFromNetwork()
}
}
19.2 流式属性委托
kotlin复制class FlowDelegate<T>(
private val flow: Flow<T>
) : ReadOnlyProperty<Any?, StateFlow<T>> {
private val state = MutableStateFlow<T?>(null)
init {
CoroutineScope(Dispatchers.Default).launch {
flow.collect { value ->
state.value = value
}
}
}
override fun getValue(thisRef: Any?, property: KProperty<*>): StateFlow<T> {
return state as StateFlow<T>
}
}
// 使用
class SensorMonitor {
val temperature: StateFlow<Float> by FlowDelegate(sensorFlow)
}
20. 委托在DSL中的应用
20.1 构建类型安全的DSL
kotlin复制class DslDelegate<T>(private val builder: DslBuilder<T>) {