本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、什么是委托?
委托是一种设计模式,让一个对象将部分职责交给另一个对象来处理。
传统方式 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}")
}
Kotlin委托详解与实现原理
1639

被折叠的 条评论
为什么被折叠?



