Kotlin委托的使用以及实现原理

Kotlin委托详解与实现原理

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、什么是委托?

委托是一种设计模式,让一个对象将部分职责交给另一个对象来处理。

传统方式 vs 委托方式

// 传统方式:手动转发所有方法
class TraditionalPrinter {
    fun printDocument() { /* 打印逻辑 */ }
}

class TraditionalComputer {
    private val printer = TraditionalPrinter()
    
    fun printDocument() {
        printer.printDocument()  // 手动转发调用
    }
}

// 委托方式:自动转发
interface PrintService {
    fun printDocument()
    fun scanDocument()
}

class AdvancedPrinter : PrintService {
    override fun printDocument() { /* 打印逻辑 */ }
    override fun scanDocument() { /* 扫描逻辑 */ }
}

class SmartComputer(printer: PrintService) : PrintService by printer {
    // 不需要手动实现所有方法,自动委托给printer
    // 可以重写特定方法或添加新方法
}

二、类委托

2.1 基础用法

// 定义接口
interface DataStorage {
    fun save(data: String)
    fun load(): String
    fun clear()
}

// 实现类
class FileStorage : DataStorage {
    private var storedData = ""
    
    override fun save(data: String) {
        storedData = data
        println("数据已保存到文件: $data")
    }
    
    override fun load(): String {
        println("从文件加载数据: $storedData")
        return storedData
    }
    
    override fun clear() {
        storedData = ""
        println("文件数据已清空")
    }
}

// 使用委托的类
class CacheManager(storage: DataStorage) : DataStorage by storage {
    // 所有 DataStorage 方法自动委托给 storage 参数
    
    // 可以添加新方法
    fun getCacheInfo(): String {
        return "缓存管理器运行中"
    }
    
    // 可以重写特定方法
    override fun save(data: String) {
        println("缓存预处理...")
        super.save(data)  // 仍然调用委托对象的方法
        println("缓存后处理...")
    }
}

// 使用
fun demonstrateClassDelegation() {
    val fileStorage = FileStorage()
    val cacheManager = CacheManager(fileStorage)
    
    cacheManager.save("用户配置数据")
    cacheManager.load()
    cacheManager.clear()
    println(cacheManager.getCacheInfo())
}

2.2 委托给多个对象

interface Logger {
    fun log(message: String)
}

interface ConfigProvider {
    fun getConfig(key: String): String?
}

class ConsoleLogger : Logger {
    override fun log(message: String) {
        println("控制台日志: $message")
    }
}

class MemoryConfig : ConfigProvider {
    private val configs = mutableMapOf<String, String>()
    
    override fun getConfig(key: String): String? {
        return configs[key].also { 
            println("获取配置: $key = $it") 
        }
    }
    
    fun setConfig(key: String, value: String) {
        configs[key] = value
    }
}

// 委托给多个接口
class ApplicationService(
    private val logger: Logger,
    private val config: ConfigProvider
) : Logger by logger, ConfigProvider by config {
    
    fun initialize() {
        log("应用服务初始化中...")
        val timeout = getConfig("timeout") ?: "30"
        log("超时设置: ${timeout}秒")
    }
    
    // 可以重写特定方法
    override fun log(message: String) {
        val timestamp = java.time.LocalDateTime.now()
        logger.log("[$timestamp] $message")
    }
}

三、属性委托

3.1 内置属性委托

3.1.1 lazy 延迟初始化
class UserProfile {
    // 基本用法 - 默认线程安全
    val userPreferences: Map<String, Any> by lazy {
        println("首次访问,加载用户偏好设置...")
        mapOf(
            "theme" to "dark",
            "language" to "zh-CN",
            "notifications" to true
        )
    }
    
    // 指定线程模式
    val heavyResource: HeavyClass by lazy(LazyThreadSafetyMode.NONE) {
        println("非线程安全模式初始化重量级资源")
        HeavyClass()
    }
    
    // 复杂初始化逻辑
    val analyticsData: List<Analytics> by lazy {
        println("初始化分析数据...")
        loadAnalyticsFromDatabase().sortedBy { it.timestamp }
    }
    
    private fun loadAnalyticsFromDatabase(): List<Analytics> {
        // 模拟数据库加载
        return listOf(
            Analytics("page_view", System.currentTimeMillis()),
            Analytics("click", System.currentTimeMillis() - 1000)
        )
    }
}

class HeavyClass {
    init {
        println("重量级资源被创建")
    }
}

data class Analytics(val event: String, val timestamp: Long)

// 使用
fun demonstrateLazy() {
    val profile = UserProfile()
    println("UserProfile对象已创建")
    
    println("首次访问userPreferences:")
    println(profile.userPreferences)
    
    println("再次访问userPreferences:")
    println(profile.userPreferences) // 不会重新初始化
}
3.1.2 observable 可观察属性
class SettingsManager {
    var volumeLevel: Int by Delegates.observable(50) { property, oldValue, newValue ->
        println("音量从 $oldValue 变更为 $newValue")
        if (newValue > 100) {
            println("警告: 音量超过安全范围!")
        }
    }
    
    var brightness: Double by Delegates.observable(0.8) { _, old, new ->
        println("屏幕亮度从 ${"%.1f".format(old)} 调整到 ${"%.1f".format(new)}")
    }
    
    var themeMode: String by Delegates.observable("light") { _, old, new ->
        println("主题从 '$old' 切换到 '$new'")
        applyTheme(new)
    }
    
    private fun applyTheme(theme: String) {
        println("应用 $theme 主题样式...")
    }
}

// 使用
fun demonstrateObservable() {
    val settings = SettingsManager()
    
    settings.volumeLevel = 75
    settings.volumeLevel = 120  // 触发警告
    settings.brightness = 0.6
    settings.themeMode = "dark"
}
3.1.3 vetoable 可否决的属性
class BankAccount {
    var balance: Double by Delegates.vetoable(0.0) { _, oldValue, newValue ->
        if (newValue < 0) {
            println("拒绝设置负数余额: $newValue")
            false  // 否决更改
        } else {
            println("余额从 $oldValue 更新为 $newValue")
            true   // 允许更改
        }
    }
    
    var accountStatus: String by Delegates.vetoable("active") { _, _, newValue ->
        val validStatuses = setOf("active", "frozen", "closed")
        if (newValue in validStatuses) {
            true  // 允许更改
        } else {
            println("无效的账户状态: $newValue")
            false // 否决更改
        }
    }
}

// 使用
fun demonstrateVetoable() {
    val account = BankAccount()
    
    account.balance = 1000.0  // 允许
    account.balance = -500.0  // 被否决
    println("当前余额: ${account.balance}")
    
    account.accountStatus = "frozen"  // 允许
    account.accountStatus = "invalid" // 被否决
}
3.1.4 notNull 非空委托
class Configuration {
    // 必须在使用前初始化,否则抛异常
    var apiKey: String by Delegates.notNull<String>()
    var serverUrl: String by Delegates.notNull<String>()
    
    fun initializeConfig(key: String, url: String) {
        apiKey = key
        serverUrl = url
    }
    
    fun makeRequest() {
        // 这里可以安全使用,因为已经初始化
        println("向 $serverUrl 发送请求,使用密钥: ${apiKey.take(5)}...")
    }
}

// 使用
fun demonstrateNotNull() {
    val config = Configuration()
    
    try {
        config.makeRequest()  // 会抛异常
    } catch (e: IllegalStateException) {
        println("捕获异常: ${e.message}")
    }
    
    config.initializeConfig("secret-key-12345", "https://api.example.com")
    config.makeRequest()  // 正常执行
}

四、自定义属性委托

4.1 基础自定义委托

import kotlin.reflect.KProperty

class SimpleDelegate<T>(private var value: T) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("获取属性 '${property.name}' = $value")
        return value
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
        println("设置属性 '${property.name}' 从 $value 到 $newValue")
        value = newValue
    }
}

// 使用自定义委托
class Product {
    var price: Double by SimpleDelegate(0.0)
    var name: String by SimpleDelegate("未命名商品")
}

fun demonstrateSimpleDelegate() {
    val product = Product()
    product.name = "智能手机"
    product.price = 2999.0
    
    println("商品: ${product.name}, 价格: ${product.price}")
}

4.2 属性验证委托

class ValidationDelegate<T>(
    private val validator: (T) -> Boolean,
    private val errorMessage: (T) -> String
) {
    private var value: T? = null
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException("属性 '${property.name}' 未初始化")
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
        if (validator(newValue)) {
            value = newValue
            println("属性 '${property.name}' 设置为: $newValue")
        } else {
            throw IllegalArgumentException("属性 '${property.name}' 验证失败: ${errorMessage(newValue)}")
        }
    }
}

class UserRegistration {
    var username: String by ValidationDelegate(
        validator = { it.length in 3..20 && it.matches(Regex("[a-zA-Z0-9_]+")) },
        errorMessage = { "用户名 '$it' 必须是3-20个字母数字字符" }
    )
    
    var email: String by ValidationDelegate(
        validator = { it.contains('@') && it.contains('.') },
        errorMessage = { "邮箱地址 '$it' 格式无效" }
    )
    
    var age: Int by ValidationDelegate(
        validator = { it in 0..150 },
        errorMessage = { "年龄 $it 必须在0-150之间" }
    )
}

fun demonstrateValidationDelegate() {
    val user = UserRegistration()
    
    try {
        user.username = "john_doe123"  // 有效
        user.email = "john@example.com" // 有效
        user.age = 25                   // 有效
        
        user.username = "ab"            // 无效 - 太短
    } catch (e: IllegalArgumentException) {
        println("验证错误: ${e.message}")
    }
    
    try {
        user.age = 200                  // 无效 - 超出范围
    } catch (e: IllegalArgumentException) {
        println("验证错误: ${e.message}")
    }
}

五、委托原理

5.1 类委托的编译原理

// 源代码
class Repository(database: Database) : Database by database

// 编译后的等效代码(概念上)
class Repository(private val `$delegate_0`: Database) : Database {
    // 编译器自动生成所有接口方法的转发
    override fun query(sql: String): Result {
        return `$delegate_0`.query(sql)
    }
    
    override fun insert(data: Map<String, Any>): Boolean {
        return `$delegate_0`.insert(data)
    }
    
    // ... 其他方法
}

5.2 属性委托的编译原理

// 源代码
class Example {
    val data: String by CustomDelegate("initial")
}

// 编译后的等效代码(概念上)
class Example {
    private val `$delegate_data` = CustomDelegate("initial")
    
    val data: String
        get() = `$delegate_data`.getValue(this, ::data)
}

5.3 委托接口分析

// Kotlin标准库中的委托相关接口
public interface ReadOnlyProperty<in T, out V> {
    public operator fun getValue(thisRef: T, property: KProperty<*>): V
}

public interface ReadWriteProperty<in T, V> {
    public operator fun getValue(thisRef: T, property: KProperty<*>): V
    public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}

// 自定义委托实现
class LoggingProperty<T>(private var value: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val className = thisRef?.javaClass?.simpleName ?: "unknown"
        println("[$className] 读取属性 '${property.name}' = $value")
        return value
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val className = thisRef?.javaClass?.simpleName ?: "unknown"
        val oldValue = this.value
        this.value = value
        println("[$className] 设置属性 '${property.name}' 从 $oldValue 到 $value")
    }
}

// 使用标准接口的实现
class Application {
    var config: String by LoggingProperty("default")
    var counter: Int by LoggingProperty(0)
}

fun demonstrateStandardInterface() {
    val app = Application()
    app.config = "production"
    println("当前配置: ${app.config}")
    app.counter = 42
    println("计数器: ${app.counter}")
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值