Home Articles

Kotlin覆盖成员设置并获取

Asked
Viewed 1147 times
4

有没有人知道在自己的基类中监听成员变更的更好方法?

class FOO {
    val t: String
}

class BOO: FOO {
    fun x(val t: String) {
        // notify when t was changed 
    }
}

在我看来,带有Observer的JavaRx将会很多 . Kotlin代表不使用继承(或者我找不到方法) . 我想出的最好的是在“BOO”中覆盖“t”的setter和getter . 但这有点尴尬因为这个“我为什么要覆盖一个成员?”或者“为什么我必须定义集合并在需要设置时获取?”

到目前为止我的解决方案:

import kotlin.properties.Delegates

fun main(args: Array<String>) {
    var foo = FOO()
    foo.t = "foo"
    foo.printT()

    var boo = BOO()
    boo.t = "boo"
    boo.printT()
}

open class FOO () {
    open var t: String? = "origin"
    set(value) {
        println("\t origin setter is called")
        field = String() + value // create a copy (original it is not a String :D)
    }
    get() {
        println("\t origin getter is called")
        return field
    }

    fun printT() = println(t)
}


class BOO (): FOO () {
    override var t: String?
    set(value) {
        // thats all what i need
        println("\t overwritten setter is called")
        super.t = value // execute origin setter
    }
    get() {
        println("\t overwritten getter is called")
        return super.t
    }
}

3 Answers

  • 4

    为什么不简单地重写?像这儿:

    open class FOO () {
        open var t: String = "origin"
    
        fun printT() = println(t)
    }
    
    class BOO (): FOO () {
        override var t: String
        get() = super.t
        set(value) {
            // thats all you need
            println("\t overwritten setter is called")
            super.t = value 
        }
    }
    

    我在这里看到的唯一缺点是需要明确地覆盖getter,但这只是一个额外的行 .

  • 2
    open class FOO {
        var t: String = "origin"
            set(value) {
                field = value
                x(t)
            }
    
        open fun x(t: String) {
            println("FOO: t=$t")
        }
    }
    
    open class BOO : FOO() {
        override fun x(t: String) {
            super.x(t)
            println("BOO: t=$t")
        }
    }
    

    UPDATE:

    我个人认为它看起来有点奇怪,但如果你所追求的不需要覆盖任何成员(字段或方法),那么你可以使你的 onChange 方法成为一个属性:

    open class FOO(val onChange: (t: String) -> Unit = FOO.defaultOnChange) {
        companion object {
            val defaultOnChange: (t: String) -> Unit = { println("FOO: t=$it") }
        }
    
        var t: String = "origin"
            set(value) {
                field = value
                onChange(t)
            }
    }
    
    open class BOO : FOO({ defaultOnChange(it); println("BOO: t=$it") })
    
  • 0

    类似的方法,但有 Delegates.observable() ,见Language reference

    import kotlin.properties.Delegates
    
    open class UserBase {
        var name: String by Delegates.observable("<no name>") { prop, old, new ->
            println("$old -> $new")
            onChange(new)
        }
    
        // could be abstract, if class is abstract
        open fun onChange(v: String?) {}
    }
    
    class User : UserBase() {
        override fun onChange(v: String?) {
            println("I was changed in my base class: ${v}")
        }
    }
    
    fun main(args: Array<String>) {
        val user = User()
        user.name = "first"
        user.name = "second"
    }
    

Related