Podes explicar o princípio de funcionamento de um delegado numa classe em Kotlin?
sobes.tech IA
Resposta da IA
Um delegado em Kotlin é um objeto que assume a execução de uma tarefa específica ou delega chamadas de métodos a outro objeto.
Cenários principais de uso:
-
Delegação de propriedades: Transferir o controlo dos getters e setters de uma propriedade para outro objeto.
lazy: Avaliação do valor da propriedade na primeira acesso.observable: Executar uma ação quando o valor da propriedade muda.vetoable: Impedir a mudança do valor da propriedade com base numa condição.
class Example { // Calculado apenas na primeira acesso val lazyValue: String by lazy { println("A calcular!") "Olá" } // É chamado em cada mudança de valor var name: String by Delegates.observable("<sem nome>") { prop, old, new -> println("O nome mudou de $old para $new") } } -
Delegação de interfaces: Implementação de uma interface através do redireccionamento de chamadas de métodos para outro objeto.
interface Base { fun print() } class BaseImpl(val x: Int) : Base { override fun print() { println(x) } } // Implementa Base, delegando chamadas a BaseImpl class Derived(b: Base) : Base by b fun main() { val b = BaseImpl(10) Derived(b).print() // Vai imprimir 10 } -
Delegação de funções: Embora não exista uma sintaxe explícita para delegar funções individuais como para propriedades ou interfaces, isso é realizado conceptualmente através de composição e chamadas de métodos de outro objeto.
Como funciona a delegação de propriedades:
O compilador Kotlin gera código auxiliar. Para uma propriedade delegada a um objeto delegate, o compilador gera uma propriedade oculta e chama os métodos getValue e setValue (para propriedades mutáveis) no objeto delegate, passando o contexto necessário (instância da classe, metadados da propriedade).
// Exemplo de pseudocódigo, como o compilador processa: val p: String by delegate
/*
private val _p: Delegate<Any?, String> = delegate_initializer
val p: String
get() = _p.getValue(this, ::p) // Chamada a getValue no delegado
*/
O objeto delegado deve ter os métodos correspondentes:
getValue(thisRef, property: KProperty<*>): Tpara propriedade do tipoT.thisRefé a instância da classe,propertysão os metadados da propriedade.setValue(thisRef, property: KProperty<*>, value: T)para propriedade mutável.
Vantagens do uso de delegados:
- Reutilização de código: A lógica comum (inicialização preguiçosa, observação de mudanças) é extraída para um delegado separado e reutilizada.
- Melhoria na legibilidade: O código torna-se menos verboso, o boilerplate fica escondido dentro do delegado.
- Modularidade: A lógica de gestão de propriedades ou implementação de interfaces é separada da lógica principal da classe.