Kotlin by关键字特性深度解析
下面我将对 by关键字的每个优势特性进行详细讲解和代码演示。
1. 简化代码:通过委托减少样板代码
传统方式 vs 委托方式对比
传统实现:大量样板代码
kotlin
// 传统方式:需要手动实现所有方法
interface DataStorage {
fun save(data: String)
fun load(): String?
fun clear()
}
class SimpleDataStorage : DataStorage {
private var storedData: String? = null
override fun save(data: String) {
storedData = data
println("数据已保存: $data")
}
override fun load(): String? {
println("加载数据: $storedData")
return storedData
}
override fun clear() {
println("清空数据")
storedData = null
}
}
// 添加日志功能的传统方式
class LoggingDataStorage : DataStorage {
private val storage = SimpleDataStorage()
override fun save(data: String) {
println("[LOG] 开始保存数据")
storage.save(data)
println("[LOG] 数据保存完成")
}
override fun load(): String? {
println("[LOG] 开始加载数据")
val result = storage.load()
println("[LOG] 数据加载完成")
return result
}
override fun clear() {
println("[LOG] 开始清空数据")
storage.clear()
println("[LOG] 数据清空完成")
}
}
委托方式:代码大幅简化
kotlin
// 使用委托:只需重写需要修改的方法
class LoggingDataStorageBy(delegate: DataStorage) : DataStorage by delegate {
override fun save(data: String) {
println("[LOG] 开始保存数据")
delegate.save(data) // 自动委托,无需手动调用其他方法
println("[LOG] 数据保存完成")
}
override fun load(): String? {
println("[LOG] 开始加载数据")
val result = delegate.load()
println("[LOG] 数据加载完成: $result")
return result
}
// clear() 方法不需要修改,自动委托给底层对象
}
// 使用示例
fun demonstrateCodeReduction() {
val simpleStorage = SimpleDataStorage()
val loggingStorage = LoggingDataStorageBy(simpleStorage)
loggingStorage.save("Hello World")
loggingStorage.load()
loggingStorage.clear() // 自动委托,无需额外代码
}
代码简化效果:
- 传统方式:需要实现 3 个方法,每个方法都要手动委托
- 委托方式:只需重写 2 个需要修改的方法,1 个方法自动委托
- 代码量减少约 40%
2. 提高复用性:将通用逻辑封装在委托中
可复用的验证逻辑委托
kotlin
import kotlin.reflect.KProperty
import kotlin.properties.ReadWriteProperty
// 可复用的范围验证委托
class RangeDelegate<T : Comparable<T>>(
private val min: T,
private val max: T,
private var value: T
) : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return value
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
require(value in min..max) {
"${property.name} 必须在 $min 到 $max 之间,当前值: $value"
}
this.value = value
}
}
// 可复用的非空验证委托
class NotNullDelegate<T : Any>(private var value: T? = null) : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return value ?: throw IllegalStateException("${property.name} 未初始化")
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.value = value
}
}
// 在多个类中复用相同的委托逻辑
class User {
var age: Int by RangeDelegate(0, 150, 25) // 年龄范围验证
var name: String by NotNullDelegate() // 非空验证
var email: String by NotNullDelegate() // 复用非空验证
}
class Product {
var price: Double by RangeDelegate(0.0, 100000.0, 0.0) // 价格范围验证
var quantity: Int by RangeDelegate(0, 1000, 0) // 数量范围验证
var sku: String by NotNullDelegate() // 复用非空验证
}
// 使用示例
fun demonstrateReusability() {
val user = User()
user.name = "张三"
user.age = 30 // 正常
// user.age = 200 // 抛出异常:年龄必须在 0 到 150 之间
val product = Product()
product.price = 99.99
product.quantity = 50
// product.quantity = -1 // 抛出异常:数量必须在 0 到 1000 之间
}
配置管理的复用
kotlin
// 可复用的配置管理委托
class ConfigDelegate<T>(
private val configKey: String,
private val defaultValue: T
) : ReadWriteProperty<Any, T> {
private val preferences by lazy {
// 模拟配置存储
mutableMapOf<String, Any>()
}
@Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return preferences[configKey] as? T ?: defaultValue
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
preferences[configKey] = value
println("配置已更新: $configKey = $value")
}
}
// 在多个配置类中复用
class AppSettings {
var theme: String by ConfigDelegate("app_theme", "light")
var language: String by ConfigDelegate("app_language", "zh-CN")
var notificationsEnabled: Boolean by ConfigDelegate("notifications", true)
}
class UserPreferences {
var fontSize: Int by ConfigDelegate("font_size", 14)
var darkMode: Boolean by ConfigDelegate("dark_mode", false)
var autoSave: Boolean by ConfigDelegate("auto_save", true)
}
3. 增强可读性:使代码意图更加清晰
声明式编程 vs 命令式编程
命令式编程(可读性差)
kotlin
class UserManager {
private var _userData: String? = null
private var _isInitialized = false
private var _lastAccessTime: Long = 0
fun getUserData(): String? {
if (!_isInitialized) {
throw IllegalStateException("UserManager 未初始化")
}
_lastAccessTime = System.currentTimeMillis()
return _userData
}
fun setUserData(data: String?) {
if (data != null && data.length > 100) {
throw IllegalArgumentException("用户数据过长")
}
_userData = data
_lastAccessTime = System.currentTimeMillis()
}
fun initialize() {
_isInitialized = true
_lastAccessTime = System.currentTimeMillis()
}
}
声明式编程(可读性好)
kotlin
class ReadableUserManager {
private var _userData: String? by NotNullDelegate()
private var _isInitialized: Boolean by NotNullDelegate()
private var _lastAccessTime: Long by NotNullDelegate()
// 使用委托明确表达意图
var userData: String? by ::_userData
.validate { it == null || it.length <= 100 } // 验证逻辑清晰
.observable { old, new ->
println("用户数据从 '$old' 变为 '$new'")
}
val isInitialized: Boolean by ::_isInitialized
val lastAccessTime: Long by ::_lastAccessTime
fun initialize() {
_isInitialized = true
_lastAccessTime = System.currentTimeMillis()
}
}
// 扩展函数增强可读性
fun <T> ReadWriteProperty<Any, T>.validate(validator: (T) -> Boolean) =
object : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return this@validate.getValue(thisRef, property)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
require(validator(value)) { "验证失败: ${property.name} = $value" }
this@validate.setValue(thisRef, property, value)
}
}
fun <T> ReadWriteProperty<Any, T>.observable(onChange: (old: T, new: T) -> Unit) =
object : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return this@observable.getValue(thisRef, property)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
val oldValue = this@observable.getValue(thisRef, property)
this@observable.setValue(thisRef, property, value)
onChange(oldValue, value)
}
}
业务逻辑的清晰表达
kotlin
// 使用委托让业务逻辑更加清晰
class BankAccount {
// 余额:自动记录交易历史
var balance: Double by TransactionalDelegate(0.0)
// 账户状态:有明确的业务规则
var status: AccountStatus by ValidatedDelegate(AccountStatus.ACTIVE) { newStatus ->
when (newStatus) {
AccountStatus.FROZEN -> balance >= 0 // 只有非负余额才能冻结
AccountStatus.CLOSED -> balance == 0.0 // 只有零余额才能关闭
else -> true
}
}
}
enum class AccountStatus { ACTIVE, FROZEN, CLOSED }
class TransactionalDelegate<T>(initialValue: T) : ReadWriteProperty<Any, T> {
private var value: T = initialValue
private val transactionHistory = mutableListOf<String>()
override fun getValue(thisRef: Any, property: KProperty<*>): T = value
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
val oldValue = this.value
this.value = value
transactionHistory.add("${property.name}: $oldValue -> $value")
println("交易记录: ${transactionHistory.last()}")
}
}
class ValidatedDelegate<T>(
initialValue: T,
private val validator: (T) -> Boolean
) : ReadWriteProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T = value
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
require(validator(value)) {
"业务规则验证失败: 不能将 ${property.name} 设置为 $value"
}
this.value = value
}
}
4. 支持多种模式
4.1 类委托模式
kotlin
// 类委托的多种应用场景
// 场景1:接口实现委托
interface Logger {
fun debug(message: String)
fun info(message: String)
fun error(message: String)
}
class ConsoleLogger : Logger {
override fun debug(message: String) = println("[DEBUG] $message")
override fun info(message: String) = println("[INFO] $message")
override fun error(message: String) = println("[ERROR] $message")
}
// 增强的日志器:只重写需要修改的方法
class EnhancedLogger(logger: Logger) : Logger by logger {
override fun error(message: String) {
println("[TIMESTAMP] ${System.currentTimeMillis()}")
logger.error("增强错误: $message")
}
// debug 和 info 方法自动委托
}
// 场景2:多接口委托
interface Serializable {
fun serialize(): String
}
interface Deserializable {
fun deserialize(data: String)
}
class DataProcessor : Logger by ConsoleLogger(), Serializable, Deserializable {
private var data: String = ""
override fun serialize(): String = data
override fun deserialize(data: String) {
this.data = data
info("数据反序列化完成: ${data.length} 字符")
}
}
4.2 属性委托模式
kotlin
// 多种属性委托应用
class PropertyDelegationExamples {
// 延迟初始化
val expensiveResource: ExpensiveResource by lazy {
println("初始化昂贵资源...")
ExpensiveResource()
}
// 可观察属性
var username: String by Delegates.observable("游客") { _, old, new ->
println("用户名从 '$old' 变为 '$new'")
}
// 可否决的属性
var age: Int by Delegates.vetoable(0) { _, old, new ->
if (new < 0) {
println("年龄不能为负数,保持原值: $old")
false
} else true
}
// 非空委托
var requiredField: String by Delegates.notNull()
}
class ExpensiveResource {
init {
Thread.sleep(1000) // 模拟昂贵初始化
println("昂贵资源初始化完成")
}
}
4.3 Map 委托模式
kotlin
// Map 委托的强大功能
// 动态配置对象
class DynamicConfig(val map: Map<String, Any>) {
val appName: String by map
val version: String by map
val timeout: Long by map
val features: List<String> by map
}
// 响应式配置对象
class ReactiveConfig(val map: MutableMap<String, Any>) {
var theme: String by map
var language: String by map
var notifications: Boolean by map
}
// 使用示例
fun demonstrateMapDelegation() {
// 从 JSON 或配置文件创建对象
val configData = mapOf(
"appName" to "MyApp",
"version" to "1.0.0",
"timeout" to 5000L,
"features" to listOf("auth", "payments", "analytics")
)
val config = DynamicConfig(configData)
println("应用: ${config.appName} v${config.version}")
println("功能: ${config.features}")
// 动态更新配置
val mutableConfig = mutableMapOf(
"theme" to "light",
"language" to "zh-CN",
"notifications" to true
)
val reactiveConfig = ReactiveConfig(mutableConfig)
reactiveConfig.theme = "dark" // 自动更新底层 Map
println("更新后的配置: $mutableConfig")
}
5. 标准委托详解
5.1 lazy 委托的三种模式
kotlin
class LazyExamples {
// 默认模式:线程安全,但可能有多余的同步开销
val defaultLazy: String by lazy {
println("默认 lazy 初始化")
"默认值"
}
// 同步模式:线程安全,使用 synchronized
val synchronizedLazy: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
println("同步 lazy 初始化")
"同步值"
}
// 发布模式:允许多次初始化,但只返回第一次成功的结果
val publicationLazy: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
println("发布模式 lazy 初始化 - 线程: ${Thread.currentThread().name}")
"发布值"
}
// 非线程安全模式:单线程环境使用,性能最高
val noneLazy: String by lazy(LazyThreadSafetyMode.NONE) {
println("非安全 lazy 初始化")
"非安全值"
}
}
// 自定义 lazy 逻辑
fun <T> lazyWithLogging(initializer: () -> T) = lazy {
println("开始延迟初始化...")
val result = initializer()
println("延迟初始化完成: $result")
result
}
class CustomLazyExample {
val data: String by lazyWithLogging {
// 模拟昂贵操作
Thread.sleep(1000)
"计算结果"
}
}
5.2 observable 和 vetoable 的高级用法
kotlin
class AdvancedObservableExamples {
// 带历史记录的观察属性
var price: Double by observableWithHistory(0.0)
// 带条件验证的观察属性
var quantity: Int by validatedObservable(0) { newValue ->
newValue >= 0 && newValue <= 1000
}
// 链式验证
var score: Int by chainValidation(0)
}
// 带历史记录的观察委托
fun <T> observableWithHistory(initialValue: T) =
object : ReadWriteProperty<Any, T> {
private var value: T = initialValue
private val history = mutableListOf<T>()
override fun getValue(thisRef: Any, property: KProperty<*>): T = value
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
val oldValue = this.value
this.value = value
history.add(value)
println("${property.name} 变更历史: ${history.joinToString(" -> ")}")
}
}
// 带验证的观察委托
fun <T> validatedObservable(
initialValue: T,
validator: (T) -> Boolean
) = object : ReadWriteProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T = value
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
require(validator(value)) { "验证失败: ${property.name} = $value" }
val oldValue = this.value
this.value = value
println("${property.name}: $oldValue -> $value")
}
}
// 链式验证委托
fun chainValidation(initialValue: Int) = object : ReadWriteProperty<Any, Int> {
private var value: Int = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): Int = value
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) {
require(value >= 0) { "分数不能为负数" }
require(value <= 100) { "分数不能超过100" }
require(value % 5 == 0) { "分数必须是5的倍数" }
this.value = value
}
}
总结对比表
| 特性 | 传统方式代码量 | 委托方式代码量 | 可读性提升 | 复用性提升 |
|---|---|---|---|---|
| 类委托 | 需要实现所有接口方法 | 只需重写需要的方法 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 属性验证 | 每个属性都需要重复代码 | 委托类封装验证逻辑 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 延迟初始化 | 手动实现双重检查锁 | 使用 lazy委托 |
⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 观察模式 | 手动实现观察者模式 | 使用 observable委托 |
⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
通过以上详细的代码示例和分析,可以看到 by关键字确实在简化代码、提高复用性、增强可读性等方面发挥了巨大作用,是 Kotlin 语言中非常强大的特性。