Kotlin委托

委托

委托 == 代理

方法内的成员永远拿不到thisRef:官方委托和自定义委托-》方法里面没办法使用反射

委托只能类委托和属性委托

Kotlin委托

本文链接:https://blog.csdn.net/feather_wch/article/details/132095759

类委托

1、类委托

  1. 委托的是接口的方法
kotlin 复制代码
// 只能用于接口
interface DB{
    fun save()
}
// 类CreateDBAction实现了接口DB,参数db是DB类型,类的实现委托给参数db。
// 目的:啥也不想干
class CreateDBAction(db: DB):DB by db

2、类委托的原理是什么?生成了什么代码?

  1. 成员变量:$$delegate_0 = 参数db
  2. 实现方法:委托给$$delegate_0调用save()
java 复制代码
public final class CreateDBAction implements DB {
   // $FF: synthetic field
   private final DB $$delegate_0;

   public CreateDBAction(@NotNull DB db) {
      Intrinsics.checkNotNullParameter(db, "db");
      super();
      this.$$delegate_0 = db;
   }

   public void save() {
      this.$$delegate_0.save();
   }
}

3、类委托有什么用?

  1. 减少委托的代码
  2. Compose是重委托
kotlin 复制代码
CreateDBAction(SqlDB()).save()
CreateDBAction(OracleDB()).save()

属性委托

1、属性委托,委托的是 属性的 set和get

kotlin 复制代码
class MyKt{
    var value = 1314
    var number by ::value // 两个属性公用get和set
}
// number -> getNumber() -> getValue()
// number = 10 -> setNumber(10) -> setValue(10)

2、委托属性有什么用?

  1. 字段升级,老字段适配老用户,新字段用于新用户。共用一个get、set
kotlin 复制代码
class Database{
    var data = 941226 // 1.0
    var newData by ::data // 2.0
}

3、懒加载委托也就是属性委托

  1. 第一次获取时,才会获取,下面例子第一次获取耗时2秒,其他都立马获得
kotlin 复制代码
fun requestDownload(): String{
    Thread.sleep(2000L)
    return "sucess"
}

// 懒加载,
// 属性委托,委托给
val responseData : String by lazy {
    requestDownload()
}
// val responseData : String = SynchronizedLazyImpl(requestDownload())
// 借助了SynchronizedLazyImpl的get方法

fun main(){
    println("startloading...")
    println(responseData)
    println(responseData)
    println(responseData)
}

自定义属性委托

1、完全自己实现属性委托

kotlin 复制代码
// 自定义委托,定义好get和set之后,属性可以用该类实现属性委托
class Custom{
    operator fun getValue(owner: Owner, property: KProperty<*>) : String{
        return "AAA"
    }
    operator fun setValue(owner: Owner, property: KProperty<*>, value :String){

    }
}
class Owner{
    val responseData : String by Custom()
}

2、利用模板实现属性委托:ReadWriteProperty

kotlin 复制代码
// 自定义委托
class Custom2 : ReadWriteProperty<Owner, String>{
    var str = "default"
    override fun getValue(thisRef: Owner, property: KProperty<*>): String {
        return str
    }
    override fun setValue(thisRef: Owner, property: KProperty<*>, value: String) {
        str = value
    }
}

提供委托/暴露者委托

1、provideDelegate

  1. 额外的属性初始化逻辑:在属性被委托对象初始化之前进行一些额外的操作,例如数据验证、计算或日志记录等。
  2. 针对不同属性的不同行为:通过在不同的委托对象的provideDelegate方法中实现不同的逻辑,可以根据属性的不同需求,为每个属性提供不同的行为。
  3. 属性访问的可扩展性:可以为属性访问添加自定义的行为,例如缓存、延迟加载、权限控制等。
kotlin 复制代码
class Owner{
    val responseData : String by Custom()
}
// 自定义委托
class Custom(var str: String = "Default") : ReadWriteProperty<Owner, String>{
    override fun getValue(thisRef: Owner, property: KProperty<*>): String {
        return str
    }
    override fun setValue(thisRef: Owner, property: KProperty<*>, value: String) {
        str = value
    }
}
// provideDelegate,暴露者委托,== 选择器
class SmartDelegator{
    operator fun provideDelegate(thisRef:Owner, property: KProperty<*>):ReadWriteProperty<Owner, String>{
        return if(property.name.isEmpty()){
            Custom("empty")
        }else{
            Custom("normal")
        }
    }
}

实战场景

自己实现by lazy

kotlin 复制代码
class LazyInitDelegate<T> {
    private var initializer: (() -> T)? = null
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return initializer?.invoke() ?: throw IllegalStateException("Property not initialized")
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: (() -> T)) {
        initializer = value
    }
}

class Example {
    val lazyProperty: String by LazyInitDelegate {
        // 在第一次访问属性时执行初始化逻辑
        println("Initializing lazy property")
        "Lazy Initialized"
    }
}

fun main() {
    val example = Example()
    println(example.lazyProperty) // 输出:Initializing lazy property \n Lazy Initialized
}

属性委托的日志记录

kotlin 复制代码
import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty

class LoggingDelegate<T> {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val value = property.getter.call()
        println("Property ${property.name} is accessed, value: $value")
        return value as T
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("Property ${property.name} is set with value: $value")
        (property as KMutableProperty).setter.call(thisRef, value)
    }
}

class Example {
    var property: String by LoggingDelegate()
}

fun main() {
    val example = Example()
    example.property = "New value" // 输出:Property property is set with value: New value
    println(example.property) // 输出:Property property is accessed, value: New value \n New value
}

viewmodel

1、如何做到属性内部可以修改,外部不可以修改?

kotlin 复制代码
class Data{
    var data:String = ""
        private set

    private void changeData(value:String){
        data = value
    }
}
val data = Data()
data.data = "" // xxx 不可以
println(data.data) // 可以

2、如何做到kotlin的list集合,对内可以修改,对外界不可以修改

kotlin 复制代码
class MyKt{
    // 内部可以修改
    private val _data : MutableList<String> = mutableListOf()
    // 外部不可以修改
    val data : List<String> by :: _data
}

3、使用::用官方自定义委托,不使用需要自定义委托

4、用委托实现ViewModel的自动构造

kotlin 复制代码
class MyViewModel : ViewModel() {
    
}

fun main() {
    // 委托实现
    val mainViewModel : MyViewModel by viewModels()
}

private fun MainActivity.viewModels() : ReadOnlyProperty<MainActivity?, MyViewModel> =
    object : ReadOnlyProperty<MainActivity?, MyViewModel>{
        override fun getValue(thisRef: MainActivity?, property: KProperty<*>): MyViewModel {
            // thisRef永远为null
            return ViewModelProvider(this@viewModels).get(MyViewModel::class.java)
        }

    }

委托TextView:类似DataBinding

kotlin 复制代码
//  
operator fun TextView.provideDelegate(value: Any?, property: KProperty<*>) =
    object: ReadWriteProperty<Any?, String?>{
        override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
            return text as String
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
            text = value
        }

    }

// 创建TextView控件,双向绑定
var textView : TextView = findViewById(R.id.tv)
var message:String ? by textView

textView.text = "更改了控件的text -> message中的数值也会变"

message = "更改了数据 -> 更新UI"

双向绑定,多个控件操作数据

kotlin 复制代码
var data1 : String by textView1
var data2 : String by textView2
var data3 : String by textView3

data3 = data2
data2 = data1
data1 = "我在吃饭哦"
// 操作数据,View就会变,不用管UI刷新数据

出题目:如何手动实现String的代理(局部变量)?(用扩展函数)

kotlin 复制代码
var s1 = "wch"
var s2 : String by ::s1 // 类的成员变量才可以
var s3 : String by s1 // 不用官方的::

fun main() {
    var s1 = "wch"
    var s2:String by s1 // 报错
}
kotlin 复制代码
// Kotlin反射机制
operator fun String.setValue(item: Any?, property: KProperty<*>, value:String){
    // import kotlin.reflect.jvm.javaField, 已经被移除
    // property.javaField?.isAccessible = true
    // property.javaField?.set(item, value)
}
operator fun String.getValue(item: Any?, property: KProperty<*>) = this
相关推荐
子玖15 小时前
实现微信扫码注册登录-基于参数二维码
后端·微信·go
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
FunnySaltyFish2 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
Kapaseker2 天前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
Kapaseker3 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z5 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton5 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream6 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam6 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker6 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin