Storia della questione:
Il pattern "Delegazione" è noto a molti linguaggi OOP, è il principio di trasferire il lavoro da un oggetto a un altro. In Java, la delegazione è implementata manualmente, attraverso un campo interno e il proxying dei metodi. In Kotlin, la delegazione è portata a livello di sintassi tramite la parola chiave by.
Problema:
L'implementazione del pattern di delegazione in Java porta a proxy class "divini", sovraccarichi di codice template e con elevate spese per la manutenzione dell'interfaccia. È difficile mantenere aggiornati i contratti delle interfacce e cambiare i delegati.
Soluzione:
Kotlin consente di creare classi che implementano un'interfaccia non direttamente, ma delegando tutti i suoi metodi a un altro oggetto tramite la scrittura class Foo(...) : MyInterface by delegateObj. Ciò consente di scrivere codice conciso e comprensibile, liberandosi della routine senza perdere flessibilità.
Esempio di codice:
interface Base { fun print() } class BaseImpl(val x: Int) : Base { override fun print() = println(x) } class Derived(b: Base) : Base by b fun main() { Derived(BaseImpl(42)).print() // 42 }
Caratteristiche chiave:
Un classe dichiarativa può modificare il comportamento di un metodo specifico, nonostante la delega?
Sì — se si implementa il metodo dell'interfaccia esplicitamente nella classe delegata (Derived), esso "sovrascriverà" il comportamento delegato per il metodo specifico.
Esempio:
class Derived(b: Base) : Base by b { override fun print() = println("Overrided!") }
È possibile delegare più interfacce a diversi oggetti?
No, in Kotlin non è possibile delegare direttamente più interfacce diverse a diversi oggetti in una singola dichiarazione. È necessario scrivere una classe con delega manuale o combinare ereditarietà e delega, se l'architettura lo consente.
La delega funziona con classi astratte o solo con interfacce?
È possibile delegare solo interfacce, non classi astratte — poiché le classi astratte possono avere stati e metodi protetti, incompatibili con la dichiarazione di delega tramite by.
Un sviluppatore implementa manualmente il pattern di delega per una decina di metodi di una grande interfaccia. Ad ogni estensione dell'interfaccia, si dimentica di aggiungere i nuovi metodi proxy. Il codice cresce, i bug si moltiplicano.
Pro:
Contro:
Viene utilizzata la sintassi by per la delegazione automatica dell'interfaccia. È facile cambiare l'implementazione e sostituire il delegato al volo, senza rischiare errori nella manutenzione del contratto.
Pro:
Contro: