Kotlin переопределить набор элементов и получить


Кто-нибудь знает лучший способ прослушивания изменений членов внутри собственного базового класса?

class FOO {
    val t: String
}

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

На мой взгляд Яваркс с наблюдателем был бы ко многому. Делегат Kotlin не работает с наследованием (или я еще не нашел способ). Лучшее, что я придумал, - это переопределить сеттер и геттер "т" в "БУ". Но это немного неудобно из-за этого "почему я должен перезаписывать член?"или "Почему я должен определить set и получить, когда мне просто нужно set?"

Итак, мое решение таково далеко:

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 4

3 ответа:

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")
    }
}

Обновление:

Лично я думаю, что это выглядит немного странно, но если вам не нужно переопределять какие-либо члены (поле или методы), то вы можете сделать свой метод 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") })

Аналогичный подход, но с Delegates.observable(), смотрите в справочник по языку:

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"
}

Почему бы не просто переопределить? Как здесь:

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 
    }
}
Единственным недостатком, который я вижу здесь, является необходимость явного переопределения геттера, но это всего лишь одна дополнительная строка.