---
title: "Delegation em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/delegation/"
markdown_url: "https://kotlin.dev.br/glossario/delegation.MD"
description: "Saiba o que é Delegation em Kotlin, como usar delegação de classe e propriedade com by para código mais limpo."
date: "2026-02-14"
author: "Karina Melo"
---

# Delegation em Kotlin: O que É e Como Funciona | Kotlin Brasil

Saiba o que é Delegation em Kotlin, como usar delegação de classe e propriedade com by para código mais limpo.


## O que é Delegation em Kotlin?

Delegation (delegação) é um padrão de design onde um objeto repassa responsabilidades para outro. Em Kotlin, a delegação é suportada **nativamente** com a palavra-chave `by`, tanto para classes quanto para propriedades.

Em vez de herdar de uma classe, você delega a implementação para uma instância. É o famoso princípio "composição sobre herança" que fica muito fácil de aplicar em Kotlin.

Pense na delegação como um gerente que distribui tarefas. O gerente (classe principal) não faz tudo sozinho -- ele delega para especialistas (objetos delegados). Quando alguém pede um relatório financeiro, o gerente repassa para o contador. O gerente sabe a quem delegar, mas não precisa saber fazer cada tarefa.

### Delegação de classe

```kotlin
interface Repositorio {
    fun salvar(dados: String)
    fun buscar(): String
}

class RepositorioBanco : Repositorio {
    override fun salvar(dados: String) = println("Salvando no banco: $dados")
    override fun buscar() = "Dados do banco"
}

class RepositorioComLog(repo: Repositorio) : Repositorio by repo {
    override fun salvar(dados: String) {
        println("[LOG] Operação de salvar iniciada")
        // Delega para o repositório original, mas nao automaticamente neste override
    }
    // buscar() é delegado automaticamente
}

fun main() {
    val repo = RepositorioComLog(RepositorioBanco())
    println(repo.buscar()) // Dados do banco
    repo.salvar("teste")   // [LOG] Operação de salvar iniciada
}
```

O `by repo` faz com que todos os métodos da [interface](/glossario/interface/) sejam delegados automaticamente. Você só sobrescreve o que quiser customizar.

### Delegação de propriedade

Kotlin oferece delegates prontos pra uso:

```kotlin
import kotlin.properties.Delegates

class Configuração {
    // Inicialização preguiçosa
    val conexao: String by lazy {
        println("Conectando ao banco...")
        "Conexão estabelecida"
    }

    // Observável — executa bloco quando muda
    var tema: String by Delegates.observable("claro") { _, antigo, novo ->
        println("Tema mudou de '$antigo' para '$novo'")
    }

    // Não pode ser lido antes de ser atribuído
    var usuario: String by Delegates.notNull()
}

fun main() {
    val config = Configuração()

    println(config.conexao) // "Conectando..." + "Conexão estabelecida"
    println(config.conexao) // "Conexão estabelecida" (já inicializou)

    config.tema = "escuro"  // Tema mudou de 'claro' para 'escuro'

    config.usuario = "Karina"
    println(config.usuario) // Karina
}
```

### Criando seu próprio delegate

```kotlin
import kotlin.reflect.KProperty

class FormatadoDelegate {
    private var valor = ""

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

class Formulario {
    var email: String by FormatadoDelegate()
}

fun main() {
    val form = Formulario()
    form.email = "  KARINA@Email.COM  "
    println(form.email) // karina@email.com
}
```

Delegation em Kotlin é poderoso pra reduzir boilerplate, adicionar comportamentos transversais e manter o código organizado.

### Delegação com múltiplas interfaces

Você pode delegar múltiplas [interfaces](/glossario/interface/) para diferentes objetos, compondo comportamentos de forma flexível:

```kotlin
interface Notificador {
    fun notificar(mensagem: String)
}

interface Auditor {
    fun registrar(acao: String)
}

class NotificadorEmail : Notificador {
    override fun notificar(mensagem: String) {
        println("Email enviado: $mensagem")
    }
}

class AuditorLog : Auditor {
    override fun registrar(acao: String) {
        println("Auditoria: $acao em ${System.currentTimeMillis()}")
    }
}

class ServicoCompleto(
    notificador: Notificador,
    auditor: Auditor
) : Notificador by notificador, Auditor by auditor

fun main() {
    val servico = ServicoCompleto(NotificadorEmail(), AuditorLog())
    servico.notificar("Pedido confirmado")
    servico.registrar("PEDIDO_CRIADO")
}
```

### Delegate para válidação de propriedades

Um caso prático é criar delegates que validam valores automaticamente:

```kotlin
import kotlin.reflect.KProperty

class Validado<T>(
    private val validacao: (T) -> Boolean,
    private val mensagemErro: String
) {
    private var valor: T? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return valor ?: throw IllegalStateException("${property.name} nao foi inicializado")
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        if (!validacao(value)) {
            throw IllegalArgumentException("$mensagemErro: $value")
        }
        valor = value
    }
}

class Cadastro {
    var idade: Int by Validado({ it in 0..150 }, "Idade invalida")
    var nome: String by Validado({ it.isNotBlank() }, "Nome nao pode ser vazio")
}

fun main() {
    val cadastro = Cadastro()
    cadastro.nome = "Karina"
    cadastro.idade = 28
    println("${cadastro.nome}, ${cadastro.idade} anos")

    try {
        cadastro.idade = -5 // Lança IllegalArgumentException
    } catch (e: IllegalArgumentException) {
        println(e.message) // Idade invalida: -5
    }
}
```

### Delegate com Map para configurações dinâmicas

Kotlin permite usar um `Map` como delegate, ideal para configurações carregadas de arquivos ou banco de dados:

```kotlin
class AppConfig(propriedades: Map<String, Any?>) {
    val nome: String by propriedades
    val versao: String by propriedades
    val debug: Boolean by propriedades
}

fun main() {
    val props = mapOf(
        "nome" to "MeuApp",
        "versao" to "3.2.1",
        "debug" to false
    )

    val config = AppConfig(props)
    println("${config.nome} v${config.versao} (debug=${config.debug})")
    // MeuApp v3.2.1 (debug=false)
}
```

### Casos de Uso no Mundo Real

- **Decorator pattern**: adicionar logging, cache ou métricas a uma implementação existente sem alterar o código original, como no exemplo `RepositorioComLog`.
- **Injeção de dependência simplificada**: delegar implementações de interfaces permite trocar comportamentos facilmente em testes.
- **Propriedades lazy em Android**: usar `by lazy` para inicializar views, adapters e outros componentes pesados somente quando necessário.
- **SharedPreferences com delegates**: criar delegates personalizados que leem e gravam valores automaticamente no SharedPreferences do Android.
- **Propriedades observáveis para UI reativa**: usar `Delegates.observable` para notificar mudanças de estado e atualizar a interface automaticamente.

### Boas Práticas

- **Prefira delegação sobre herança**: quando você precisa reutilizar comportamento, considere delegar para uma instância em vez de criar uma hierarquia de classes.
- **Use `by lazy` para inicializações caras**: propriedades que envolvem leitura de arquivo, conexão de banco ou cálculos pesados devem ser lazy.
- **Mantenha delegates simples**: cada delegate deve ter uma única responsabilidade.
- **Use [property delegates](/glossario/property-delegate/) padrão** antes de criar os seus. `lazy`, `observable`, `notNull` e `vetoable` cobrem a maioria dos casos.

### Erros Comuns

- **Esquecer de chamar o método original no override**: ao sobrescrever um método delegado, o `by` não repassa automaticamente. Você precisa manter uma referência ao objeto delegado se quiser chamar a implementação original.
- **Usar `by lazy` com `var`**: `lazy` só funciona com `val`, pois o valor é computado uma única vez. Para propriedades mutáveis, use `Delegates.observable` ou `Delegates.vetoable`.
- **Ciclos de dependência em delegates**: se dois delegates dependem um do outro, você pode causar um loop infinito ou `StackOverflowError`.
- **Não considerar thread safety com `lazy`**: por padrão, `lazy` é sincronizado (`LazyThreadSafetyMode.SYNCHRONIZED`). Se você tem certeza de que a propriedade será acessada por uma única thread, use `lazy(LazyThreadSafetyMode.NONE)` para melhor performance.

### Perguntas Frequentes

**Qual a diferença entre delegation e herança?**
Herança cria uma relação "é um" (is-a), enquanto delegação cria uma relação "tem um" (has-a). Delegação é mais flexível porque permite trocar o comportamento em tempo de execução e evita os problemas da herança múltipla.

**Posso delegar para uma propriedade mutável?**
Sim, mas cuidado. Se você usa `var` para o objeto delegado, trocar a referência não atualiza a delegação, pois o `by` captura a referência no momento da construção.

**O que é `Delegates.vetoable`?**
É similar ao `observable`, mas permite rejeitar a mudança de valor. A [lambda](/glossario/lambda/) retorna `Boolean`: se retornar `false`, o valor não é atualizado.

**Delegação de classe funciona com classes abstratas?**
Não. A delegação com `by` só funciona com [interfaces](/glossario/interface/). Você não pode usar `by` para delegar a implementação de uma classe abstrata ou concreta.
