Scrivere un delegato ReadWriteProperty personalizzato
Implementi da zero un delegato di proprietà personalizzato usando ReadWriteProperty.
Scrivere un delegato ReadWriteProperty personalizzato è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.
L'interfaccia ReadWriteProperty
Un delegato personalizzato implementa ReadWriteProperty<ThisRef, T> con gli operatori getValue e 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 per val
Per le proprietà val di sola lettura, implementi ReadOnlyProperty<ThisRef, T> usando solo 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) }Usare thisRef per il contesto
thisRef consente al delegato di accedere all'oggetto che lo contiene, abilitando un comportamento sensibile al contesto.
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) }Delegato numerico con limite
Un delegato che limita un valore numerico a un intervallo, applicando gli invarianti in modo trasparente.
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
}Delegato per una cache nullable
Un delegato che calcola un valore una volta e lo memorizza, con la possibilità di invalidarlo impostandolo su null.
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
}Delegato thread-safe con @Synchronized
Aggiunga la sicurezza dei thread a un delegato con @Synchronized o con un oggetto lock interno.
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) }Modello di funzione factory per delegati
Esponga un delegato tramite una funzione di estensione che restituisce l'oggetto delegato, seguendo lo stile della libreria standard.
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" }Delegato con metadati KProperty
L'argomento KProperty fornisce il nome della proprietà e le annotazioni, risultando utile per i framework di logging o gli ORM.
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 */ }Operatore provideDelegate
provideDelegate consente a un delegato di intercettare la configurazione della delega e convalidare il nome della proprietà o le annotazioni al momento dell'inizializzazione.
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) }Confronto tra gli approcci
Delegati personalizzati rispetto a observable/vetoable: usi quelli integrati per semplici modelli reattivi; scriva delegati personalizzati per invarianti complessi, caching o comportamenti sensibili al contesto.
// 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) }Pratica: delegato SharedPreferences
Un pattern comune in Android: delegare una proprietà a SharedPreferences, in modo che letture e scritture vengano salvate su disco in modo trasparente.
// 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())
}Verifica rapida
Quale interfaccia deve implementare un delegato di lettura e scrittura?
Riepilogo
I delegati personalizzati implementano ReadWriteProperty (o ReadOnlyProperty) e possono incapsulare registrazione, caching, convalida, limitazione dei valori o archiviazione sulla piattaforma dietro un'interfaccia di proprietà trasparente.
Domande Frequenti
La lezione «Scrivere un delegato ReadWriteProperty personalizzato» è gratuita?
Sì — il testo completo di «Scrivere un delegato ReadWriteProperty personalizzato» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.
Cosa imparerò in «Scrivere un delegato ReadWriteProperty personalizzato»?
Implementi da zero un delegato di proprietà personalizzato usando ReadWriteProperty. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Kotlin Academy?
Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Scrivere un delegato ReadWriteProperty personalizzato»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?
Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- by lazy: approfondimento sull'inizializzazione differita
- Delegati observable e vetoable
- Scrivere un delegato ReadWriteProperty personalizzato
- Delegati per Preferences, proprietà basate su Map e logging