Kotlin Academy · Aula

Escrevendo um delegado ReadWriteProperty personalizado

Implemente um delegado de propriedade personalizado do zero usando ReadWriteProperty.

Aula 3 de 413 etapas

Escrevendo um delegado ReadWriteProperty personalizado é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.

A interface ReadWriteProperty

Um delegado personalizado implementa ReadWriteProperty<ThisRef, T> com operadores 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 para val

Para propriedades val somente leitura, implemente ReadOnlyProperty<ThisRef, T> usando apenas 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) }

Usando thisRef para obter contexto

thisRef dá ao delegado acesso ao objeto que o contém, permitindo um comportamento sensível ao contexto.

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

Delegado numérico limitado

Um delegado que limita um valor numérico a um intervalo, impondo invariantes de forma transparente.

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
}

Delegado de cache anulável

Um delegado que calcula um valor uma vez e o armazena em cache, com a possibilidade de invalidá-lo atribuindo nulo.

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
}

Delegado seguro para threads com @Synchronized

Adicione segurança entre threads a um delegado com @Synchronized ou um objeto de bloqueio 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) }

Padrão de função fábrica de delegados

Exponha um delegado por meio de uma função de extensão que retorna o objeto delegado, seguindo o estilo da biblioteca padrão.

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

Delegado com metadados de KProperty

O argumento KProperty fornece o nome e as anotações da propriedade, sendo útil para estruturas de registro ou 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 */ }

Operador provideDelegate

provideDelegate permite que um delegado intercepte a configuração da delegação e valide o nome ou as anotações da propriedade durante a inicialização.

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

Comparando abordagens

Delegados personalizados versus observable/vetoable: use os recursos integrados para padrões reativos simples; escreva delegados personalizados para invariantes complexas, armazenamento em cache ou comportamentos sensíveis ao contexto.

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

Prática: delegado de SharedPreferences

Um padrão comum no Android: delegue uma propriedade a SharedPreferences para que as leituras e gravações sejam persistidas de forma transparente no disco.

// 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ção rápida

Qual interface um delegado de leitura e escrita deve implementar?

Revisão

Delegados personalizados implementam ReadWriteProperty (ou ReadOnlyProperty) e podem encapsular registro, armazenamento em cache, validação, limitação de valores ou armazenamento da plataforma por trás de uma interface transparente de propriedade.

Grátis para começar

Aprenda Kotlin com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
51
Aulas
203

Perguntas Frequentes

A aula “Escrevendo um delegado ReadWriteProperty personalizado” é grátis?

Sim — o texto completo de “Escrevendo um delegado ReadWriteProperty personalizado” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.

O que vou aprender em “Escrevendo um delegado ReadWriteProperty personalizado”?

Implemente um delegado de propriedade personalizado do zero usando ReadWriteProperty. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Kotlin Academy?

Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Escrevendo um delegado ReadWriteProperty personalizado”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Kotlin Academy?

Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. by lazy: análise detalhada da inicialização adiada
  2. Delegados observable e vetoable
  3. Escrevendo um delegado ReadWriteProperty personalizado
  4. Delegados para preferências, propriedades baseadas em mapas e registro
← Voltar para Kotlin Academy