2016-05-03 35 views
6

Supponiamo che io abbia una specifica molto intricato definito come interfaccia:Kotlin delegazione espressione invece di riferimento fisso

interface Spec { 
    fun sayHello() 
} 

E un'implementazione standard:

class Impl(private val msg: String) : Spec { 
    override fun sayHello() { 
     println(msg) 
    } 
} 

Supponiamo ora che voglio creare un classe che implementa questa specifica e delega a un'implementazione, ma l'oggetto delegato esatto è mutabile per tutta la durata dell'oggetto. Ecco un esempio:

class Derived(var target: Spec) : Spec by target 

Il problema con l'esempio di cui sopra è che l'argomento del costruttore target è impostata come oggetto delegato quando il costruttore viene chiamato. Il delegato viene quindi visitato direttamente dalla classe invece di eseguire un accesso a una proprietà. (Ciò è stato confermato guardando il bytecode prodotto da Kotlin.)

Quindi, anche se la proprietà target viene modificata dopo la creazione della classe, il delegato non cambia.

Qualcuno può fornire un metodo per eseguire questa delega in Kotlin senza dover scrivere ogni singolo metodo?

Una soluzione ideale consentirebbe inoltre la delega a qualcosa di generale come un lambda o altra espressione che verrebbe valutata e utilizzata come delegato ogni volta che il delegato è necessario per tutta la durata dell'oggetto.

risposta

6

In questo momento non c'è modo di farlo. Vedere Kotlin issue KT-5870

currenlty Kotlin valuta espressione per delegato della classe di inizializzazione

0

È possibile aggiungere un livello di indirezione:

class Holder(var impl: Spec) : Spec { 
    override fun sayHello() = impl.sayHello()  
} 

class Derived(target: Spec, 
       private val holder: Holder = Holder(target)) : Spec by holder { 

    fun changeTarget(newTarget: Spec) { 
     holder.impl = newTarget 
    } 
} 

Purtroppo holder deve essere un parametro del costruttore, al fine di essere utilizzato con il costrutto di delega (come per Kotlin v1.0), quindi complica il costruttore principale.

+1

In questo caso è necessario delegare manualmente tutti i metodi che l'autore sta cercando di evitare. – Michael

+0

@Michael si, è vero, tuttavia devo solo eseguire la delega manuale una sola volta per 'Holder', dopodiché posso usarlo senza nessun file aggiuntivo – voddan

+0

Non hai bisogno di alcuna classe aggiuntiva per quello. È sufficiente delegare tutto direttamente da "Derived". – Michael