0Pricing
Kotlin Academy · Lektion

Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben

Implementieren Sie einen benutzerdefinierten Property-Delegate von Grund auf mit ReadWriteProperty.

Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben ist eine kostenlose Kotlin Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Kotlin Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Kotlin Academy-Kurs umfasst insgesamt 4 Lektionen.

Das ReadWriteProperty-Interface

Ein benutzerdefinierter Delegate implementiert ReadWriteProperty<ThisRef, T> mit den Operatoren getValue und setValue.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SimpleDelegate<T>(private var value: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}
var x: Int by SimpleDelegate(0)
fun main() { x = 42; println(x) }

ReadOnlyProperty für val

Für schreibgeschützte val-Properties implementieren Sie ReadOnlyProperty<ThisRef, T> nur mit getValue.

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class Constant<T>(private val value: T) : ReadOnlyProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
}
val pi: Double by Constant(3.14159)
fun main() { println(pi) }

thisRef für den Kontext verwenden

thisRef ermöglicht dem Delegate den Zugriff auf das umschließende Objekt und damit kontextabhängiges Verhalten.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class LoggingDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("[${thisRef?.javaClass?.simpleName}] get ${property.name} = $v")
        return v
    }
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("[${thisRef?.javaClass?.simpleName}] set ${property.name} = $value")
        v = value
    }
}
class Config { var host: String by LoggingDelegate("localhost") }
fun main() { val c = Config(); c.host = "prod.example.com"; println(c.host) }

Delegate zur Begrenzung numerischer Werte

Ein Delegate, der einen numerischen Wert auf einen Wertebereich begrenzt und so Invarianten transparent durchsetzt.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Clamped(private val min: Int, private val max: Int, initial: Int) : ReadWriteProperty<Any?, Int> {
    private var v = initial.coerceIn(min, max)
    override fun getValue(t: Any?, p: KProperty<*>) = v
    override fun setValue(t: Any?, p: KProperty<*>, value: Int) {
        v = value.coerceIn(min, max)
    }
}
var brightness: Int by Clamped(0, 255, 128)
fun main() {
    brightness = 300; println(brightness) // 255
    brightness = -5;  println(brightness) // 0
    brightness = 100; println(brightness) // 100
}

Nullable-Cache-Delegate

Ein Delegate, der einen Wert einmal berechnet und zwischenspeichert und durch Setzen auf null invalidiert werden kann.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class CachedNullable<T>(private val compute: () -> T) : ReadWriteProperty<Any?, T?> {
    private var cache: T? = null
    override fun getValue(t: Any?, p: KProperty<*>): T? = cache ?: compute().also { cache = it }
    override fun setValue(t: Any?, p: KProperty<*>, value: T?) { cache = value }
}
var expensiveResult: Int? by CachedNullable { (1..1000).sum() }
fun main() {
    println(expensiveResult) // computed
    println(expensiveResult) // cached
    expensiveResult = null
    println(expensiveResult) // recomputed
}

Thread-sicherer Delegate mit @Synchronized

Fügen Sie einem Delegate mit @Synchronized oder einem internen Sperrobjekt Thread-Sicherheit hinzu.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SynchronizedDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    @Synchronized
    override fun getValue(t: Any?, p: KProperty<*>) = v
    @Synchronized
    override fun setValue(t: Any?, p: KProperty<*>, value: T) { v = value }
}
var counter: Int by SynchronizedDelegate(0)
fun main() { counter = 99; println(counter) }

Muster für eine Delegate-Factory-Funktion

Stellen Sie einen Delegate über eine Erweiterungsfunktion bereit, die das Delegate-Objekt zurückgibt, entsprechend dem Stil der Standardbibliothek.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun <T> logged(initial: T): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
    var v = initial
    override fun getValue(t: Any?, p: KProperty<*>): T { println("get ${p.name}"); return v }
    override fun setValue(t: Any?, p: KProperty<*>, value: T) { println("set ${p.name}=$value"); v = value }
}
var name: String by logged("world")
fun main() { println(name); name = "Kotlin" }

Delegate mit KProperty-Metadaten

Das Argument KProperty stellt den Property-Namen und die Annotationen bereit und ist nützlich für Logging-Frameworks oder ORMs.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class AuditDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    private val history = mutableListOf<String>()
    override fun getValue(t: Any?, p: KProperty<*>) = v
    override fun setValue(t: Any?, p: KProperty<*>, value: T) {
        history.add("${p.name}: $v -> $value")
        v = value
    }
    fun printHistory() = history.forEach(::println)
}
var status: String by AuditDelegate("idle").also { /* expose audit */ }

provideDelegate-Operator

provideDelegate ermöglicht es einem Delegate, den Aufbau der Delegation abzufangen und den Property-Namen oder Annotationen zum Zeitpunkt der Initialisierung zu validieren.

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class ValidatedDelegate<T>(private val v: T) {
    operator fun provideDelegate(t: Any?, p: KProperty<*>): ReadOnlyProperty<Any?, T> {
        require(p.name.isNotBlank()) { "Property name must not be blank" }
        return ReadOnlyProperty { _, _ -> v }
    }
}
val greeting: String by ValidatedDelegate("Hello")
fun main() { println(greeting) }

Ansätze vergleichen

Benutzerdefinierte Delegates im Vergleich zu observable/vetoable: Verwenden Sie die integrierten Funktionen für einfache reaktive Muster; schreiben Sie benutzerdefinierte Delegates für komplexe Invarianten, Caching oder kontextabhängiges Verhalten.

// Built-in: simple change notification
import kotlin.properties.Delegates
var simple: Int by Delegates.observable(0) { _,_,v -> println("changed: $v") }
// Custom: clamping + logging
var complex: Int by run {
    object : kotlin.properties.ReadWriteProperty<Any?,Int> {
        var v = 0
        override fun getValue(t:Any?,p:kotlin.reflect.KProperty<*>)=v
        override fun setValue(t:Any?,p:kotlin.reflect.KProperty<*>,value:Int){
            println("clamping $value"); v=value.coerceIn(0,100)
        }
    }
}
fun main() { simple=5; complex=200; println(complex) }

Praktisch: SharedPreferences-Delegate

Ein gängiges Android-Muster: Delegieren Sie eine Property an SharedPreferences, damit Lese- und Schreibzugriffe transparent auf der Festplatte gespeichert werden.

// Pseudocode (no Android runtime here)
class PrefDelegate(private val key: String, private val default: String) {
    // In real Android code:
    // override fun getValue(...) = prefs.getString(key, default) ?: default
    // override fun setValue(...) { prefs.edit().putString(key, value).apply() }
    fun getValue(): String = default // simplified
}
fun main() {
    val delegate = PrefDelegate("user_name", "Guest")
    println(delegate.getValue())
}

Schnelltest

Welches Interface muss ein Read-write-Delegate implementieren?

Zusammenfassung

Benutzerdefinierte Delegates implementieren ReadWriteProperty (oder ReadOnlyProperty) und können Logging, Caching, Validierung, Wertebegrenzung oder Plattformspeicher hinter einer transparenten Property-Schnittstelle kapseln.

Häufig gestellte Fragen

Ist die Lektion „Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben“ kostenlos?

Ja — der vollständige Text von „Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Kotlin Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Kotlin Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben“?

Implementieren Sie einen benutzerdefinierten Property-Delegate von Grund auf mit ReadWriteProperty. Du übst Kotlin Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Kotlin Academy zu starten?

Keine Vorkenntnisse erforderlich. Kotlin Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Kotlin Academy-Lektion Code schreiben und ausführen?

Ja. Jede Kotlin Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. by lazy: Vertiefung zur verzögerten Initialisierung
  2. observable- und vetoable-Delegates
  3. Einen benutzerdefinierten ReadWriteProperty-Delegate schreiben
  4. Delegates für Preferences, Map-basierte Properties und Logging
← Zurück zu Kotlin Academy