---
title: "Delegação de Propriedades em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil"
url: "https://kotlin.dev.br/tutoriais/delegacao-propriedades/"
markdown_url: "https://kotlin.dev.br/tutoriais/delegacao-propriedades.MD"
description: "Aprenda delegação de propriedades em Kotlin: by, lazy, observable, vetoable, map delegation e delegates customizados com exemplos práticos."
date: "2026-03-17"
author: "Karina Melo"
---

# Delegação de Propriedades em Kotlin Tutorial em Português — Passo a Passo | Kotlin Brasil

Aprenda delegação de propriedades em Kotlin: by, lazy, observable, vetoable, map delegation e delegates customizados com exemplos práticos.


Neste tutorial, você vai aprender tudo sobre **delegação de propriedades em Kotlin** — um recurso elegante que permite reutilizar lógica de acesso a propriedades sem repetir código. Vamos explorar a palavra-chave `by`, os delegates da standard library como `lazy`, `observable` e `vetoable`, delegação via Map e como criar seus próprios delegates customizados. Se você já conhece [classes e objetos](/tutoriais/classes-e-objetos-kotlin/) e [lambdas](/tutoriais/lambdas-kotlin/), esta pronto para esse topico.

## O que é Delegação de Propriedades?

Em Kotlin, uma propriedade normalmente armazena seu valor em um campo (backing field). Mas as vezes você precisa de comportamento extra toda vez que o valor e lido ou escrito — logar a mudanca, validar o novo valor, calcular sob demanda, buscar de um cache e por aí vai.

Você poderia escrever getters e setters customizados, mas se essa mesma lógica se repete em várias propriedades ou classes, o código fica duplicado. A [delegação de propriedades](/glossario/property-delegate/) resolve esse problema: você delega o armazenamento é o acesso da propriedade para outro objeto usando a palavra-chave `by`.

```kotlin
class Exemplo {
    var texto: String by MeuDelegate()
}
```

Quando alguem lê `exemplo.texto`, o Kotlin chama o método `getValue()` do delegate. Quando alguem escreve `exemplo.texto = "novo"`, o Kotlin chama `setValue()`. O objeto delegate encapsula toda a lógica.

## lazy: Inicialização Preguicosa

O delegate mais usado do Kotlin e provavelmente o `lazy`. Ele adia a inicialização de uma propriedade até o momento em que ela e acessada pela primeira vez. Depois disso, o valor calculado fica em cache e e retornado diretamente nas leituras seguintes.

```kotlin
class ConfiguracaoApp {
    val dadosPesados: List<String> by lazy {
        println("Carregando dados... (so acontece uma vez)")
        carregarDoBancoDeDados()
    }

    private fun carregarDoBancoDeDados(): List<String> {
        // Simula uma operacao custosa
        return listOf("config1", "config2", "config3")
    }
}

fun main() {
    val config = ConfiguracaoApp()
    println("Objeto criado, dados ainda nao carregados")
    println(config.dadosPesados) // Aqui o bloco lazy e executado
    println(config.dadosPesados) // Aqui usa o cache
}
```

Por padrão, `lazy` e thread-safe (usa `LazyThreadSafetyMode.SYNCHRONIZED`). Se você sabe que a propriedade sera acessada apenas por uma thread, pode usar `lazy(LazyThreadSafetyMode.NONE)` para evitar o custo de sincronizacao:

```kotlin
val valor: String by lazy(LazyThreadSafetyMode.NONE) {
    "Inicializado sem sincronizacao"
}
```

O `lazy` só funciona com [val](/glossario/val/), já que o valor e calculado uma única vez e nunca muda depois disso. Para cenários onde você precisa de inicialização tardia com `var`, considere usar [lateinit](/glossario/lateinit/).

## observable: Reagindo a Mudancas

O delegate `Delegates.observable()` permite executar um callback toda vez que o valor de uma propriedade muda. E muito útil para atualizar a interface, logar mudancas ou notificar outros componentes.

```kotlin
import kotlin.properties.Delegates

class Carrinho {
    var quantidadeItens: Int by Delegates.observable(0) { propriedade, valorAntigo, valorNovo ->
        println("${propriedade.name} mudou de $valorAntigo para $valorNovo")
        atualizarBadge(valorNovo)
    }

    private fun atualizarBadge(quantidade: Int) {
        println("Badge atualizado: $quantidade itens")
    }
}

fun main() {
    val carrinho = Carrinho()
    carrinho.quantidadeItens = 3  // Imprime a mudanca e atualiza o badge
    carrinho.quantidadeItens = 7  // Idem
}
```

O callback recebe tres parametros: a referência a propriedade (`KProperty`), o valor antigo e o valor novo. Importante: o callback e chamado **depois** que o valor já foi atribuido.

## vetoable: Validando Antes de Atribuir

Se você precisa validar um valor **antes** de aceita-lo, use `Delegates.vetoable()`. O callback retorna `true` para aceitar a mudanca ou `false` para rejeita-la, mantendo o valor anterior.

```kotlin
import kotlin.properties.Delegates

class Conta {
    var saldo: Double by Delegates.vetoable(0.0) { _, valorAntigo, valorNovo ->
        if (valorNovo < 0) {
            println("Operação negada: saldo nao pode ser negativo (tentou: $valorNovo)")
            false
        } else {
            println("Saldo atualizado: $valorAntigo -> $valorNovo")
            true
        }
    }
}

fun main() {
    val conta = Conta()
    conta.saldo = 1000.0  // Aceito
    conta.saldo = 500.0   // Aceito
    conta.saldo = -200.0  // Rejeitado, saldo continua 500.0
    println("Saldo final: ${conta.saldo}") // 500.0
}
```

Esse padrão e particularmente útil para propriedades que representam configurações ou limites que não devem ultrapassar certos valores.

## Delegação por Map

Um caso de uso muito prático e delegar propriedades para um `Map`. Isso e especialmente útil ao trabalhar com dados dinâmicos, como JSON parseado ou configurações carregadas de um arquivo.

```kotlin
class Usuario(dados: Map<String, Any?>) {
    val nome: String by dados
    val email: String by dados
    val idade: Int by dados
}

fun main() {
    val mapa = mapOf(
        "nome" to "Carlos Oliveira",
        "email" to "carlos@email.com",
        "idade" to 32
    )

    val usuario = Usuario(mapa)
    println("${usuario.nome}, ${usuario.email}, ${usuario.idade}")
    // Carlos Oliveira, carlos@email.com, 32
}
```

O Kotlin usa o nome da propriedade como chave no mapa. Para propriedades mutaveis (`var`), basta usar `MutableMap`:

```kotlin
class Configuração(dados: MutableMap<String, Any?>) {
    var tema: String by dados
    var fontSize: Int by dados
}

fun main() {
    val dados = mutableMapOf<String, Any?>(
        "tema" to "escuro",
        "fontSize" to 14
    )

    val config = Configuração(dados)
    config.tema = "claro"
    println(dados["tema"]) // "claro" — o mapa e atualizado
}
```

Esse padrão e uma alternativa elegante ao uso de [data classes](/tutoriais/data-classes-tutorial/) quando a estrutura dos dados não e conhecida em tempo de compilação.

## Criando Delegates Customizados

Para criar seu próprio delegate, você precisa implementar as interfaces `ReadOnlyProperty` (para `val`) ou `ReadWriteProperty` (para `var`):

```kotlin
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class TrimDelegate : ReadWriteProperty<Any?, String> {
    private var valor: String = ""

    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return valor
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        valor = value.trim()
    }
}

class Formulario {
    var nome: String by TrimDelegate()
    var email: String by TrimDelegate()
}

fun main() {
    val form = Formulario()
    form.nome = "  Maria Silva  "
    form.email = "  maria@email.com  "
    println("'${form.nome}'")   // 'Maria Silva'
    println("'${form.email}'")  // 'maria@email.com'
}
```

O `TrimDelegate` automaticamente remove espacos em branco das pontas toda vez que um valor e atribuido. Esse tipo de lógica reutilizavel e o ponto forte da delegação.

## Caso Prático: SharedPreferences Delegate

No desenvolvimento Android, um dos usos mais elegantes de delegates customizados e encapsular o acesso a SharedPreferences. Em vez de repetir chamadas `getString()`, `putString()` e afins espalhadas pelo código, você cria um delegate que faz isso transparentemente.

```kotlin
import android.content.SharedPreferences
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class StringPreference(
    private val prefs: SharedPreferences,
    private val chave: String,
    private val valorPadrao: String = ""
) : ReadWriteProperty<Any?, String> {

    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return prefs.getString(chave, valorPadrao) ?: valorPadrao
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        prefs.edit().putString(chave, value).apply()
    }
}

// Função auxiliar para facilitar o uso
fun SharedPreferences.string(chave: String, padrao: String = "") =
    StringPreference(this, chave, padrao)

// Uso
class Preferencias(prefs: SharedPreferences) {
    var nomeUsuario: String by prefs.string("nome_usuario")
    var tema: String by prefs.string("tema", "escuro")
    var idioma: String by prefs.string("idioma", "pt-BR")
}
```

Repare como a [extension function](/tutoriais/extension-functions-tutorial/) `string()` torna a declaracao das propriedades extremamente limpa. Quem usa a classe `Preferencias` nem precisa saber que por tras dos panos os dados estao sendo persistidos em SharedPreferences.

## Caso Prático: Delegate com Log para ViewModel

Outro cenário comum e criar um delegate que loga todas as mudancas de estado em um [ViewModel](/glossario/viewmodel/):

```kotlin
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class LoggedProperty<T>(
    private var valor: T,
    private val tag: String = "ViewModel"
) : ReadWriteProperty<Any?, T> {

    override fun getValue(thisRef: Any?, property: KProperty<*>): T = valor

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("[$tag] ${property.name}: $valor -> $value")
        valor = value
    }
}

fun <T> logged(valorInicial: T, tag: String = "ViewModel") =
    LoggedProperty(valorInicial, tag)

// Uso
class PedidoViewModel {
    var status: String by logged("pendente", "PedidoVM")
    var total: Double by logged(0.0, "PedidoVM")
}

fun main() {
    val vm = PedidoViewModel()
    vm.status = "processando"
    // [PedidoVM] status: pendente -> processando
    vm.total = 149.90
    // [PedidoVM] total: 0.0 -> 149.90
}
```

Esse tipo de delegate e muito útil durante o desenvolvimento para rastrear mudancas de estado sem poluir a lógica de negocios com chamadas de log.

## Combinando Delegates

Uma técnica avançada e combinar delegates. Por exemplo, uma propriedade que e `lazy` na primeira leitura mas `observable` nas escritas subsequentes. Embora a standard library não oferca isso diretamente, você pode implementar o comportamento que precisar criando seu próprio delegate:

```kotlin
class LazyObservable<T>(
    private val inicializador: () -> T,
    private val onChange: (antigo: T, novo: T) -> Unit
) : ReadWriteProperty<Any?, T> {

    private var valor: T? = null
    private var inicializado = false

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (!inicializado) {
            valor = inicializador()
            inicializado = true
        }
        @Suppress("UNCHECKED_CAST")
        return valor as T
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val antigo = if (inicializado) valor as T else inicializador()
        valor = value
        inicializado = true
        onChange(antigo, value)
    }
}
```

## Quando Usar Delegação de Propriedades

A delegação de propriedades brilha nos seguintes cenários:

- **Inicialização preguicosa**: quando calcular o valor inicial e custoso e pode não ser necessário. Use `lazy`.
- **Observacao de mudancas**: quando outros componentes precisam ser notificados. Use `observable`.
- **Validação**: quando valores precisam ser verificados antes da atribuicao. Use `vetoable`.
- **Persistencia transparente**: SharedPreferences, banco de dados ou cache sem poluir o código de negocios.
- **Dados dinâmicos**: quando a estrutura vem de um mapa ou JSON. Use delegação por Map.

Evite usar delegates em excesso ou para lógica trivial. Se um getter ou setter simples resolve, não há necessidade de abstrair com delegação. Como em tudo no desenvolvimento de software, o bom senso e a melhor ferramenta.

## Conclusão

A delegação de propriedades e um dos recursos mais elegantes do Kotlin e exemplifica bem a filosofia da linguagem de reduzir boilerplate sem sacrificar clareza. Com `lazy`, `observable`, `vetoable` e delegates customizados, você consegue encapsular comportamentos complexos de forma reutilizavel e transparente.

Se você quer se aprofundar em padrões de delegação de forma mais ampla — incluindo delegação de classes com `by` — consulte a entrada sobre [delegation](/glossario/delegation/) no glossario. E para ver delegates em acao dentro de arquiteturas reais, confira o tutorial sobre [MVVM](/tutoriais/kotlin-mvvm-tutorial/), onde delegates como `lazy` e observables são amplamente utilizados.
