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
相关推荐
唐棣棣1 分钟前
C++:单例模式
开发语言·c++·单例模式
xiaocaibao7779 分钟前
Bash语言的语法
开发语言·后端·golang
小怪瘦7915 分钟前
JS实现Table表格数据跑马灯效果
开发语言·javascript·信息可视化
智多星00118 分钟前
c++Qt登录页面设计
开发语言·c++·qt
吾与谁归in34 分钟前
【C#学习——特性】
开发语言·c#
code monkey.34 分钟前
【探寻C++之旅】第一章:C++入门
开发语言·c++
yava_free1 小时前
指定Bean加载顺序的能力
java·开发语言
程序员老冯头1 小时前
第二十三章 C++ 继承
开发语言·数据结构·c++·算法·继承
whisperrr.1 小时前
探索JDBC:Java数据库连接的艺术与魅力
java·开发语言·数据库
非凡的世界1 小时前
使用PHP函数 “setcookie“ 设置cookie
开发语言·php