In Kotlin classi astratte (abstract class) e interfacce (interface) vengono utilizzate per dichiarare logica astratta, ma ci sono differenze sostanziali tra di esse:
abstract class Animal(val name: String) { abstract fun makeSound() fun info() = println("I am $name") } interface Movable { fun move() } class Cat(name: String) : Animal(name), Movable { override fun makeSound() = println("Meow") override fun move() = println("Cat moves") }
Un'interfaccia in Kotlin può contenere stati (backing field)?
La maggior parte risponde che si possono dichiarare proprietà in un'interfaccia, ma esse non hanno comunque un backing field — solo getter/setter senza memorizzazione del valore. Anche se si scrive get() = ... — il valore verrà calcolato ogni volta.
Esempio:
interface MyInterface { val value: Int get() = 42 // nessuna memorizzazione del valore, calcolo al volo }
Storia
In un grande progetto, uno sviluppatore senior cercava di memorizzare uno stato in un'interfaccia (ad esempio, un contatore), aspettandosi che la proprietà var count: Int avesse un backing field. Di conseguenza, tutte le classi implementatrici dell'interfaccia dovevano implementare la memorizzazione del valore in modi diversi, il che ha portato a logiche instabili (i dati andavano persi se si dimenticava di sovrascrivere il setter).
Storia
Uno degli sviluppatori usava una classe astratta dove era necessaria un'implementazione multipla di diverse strategie comportamentali (pattern strategia). Di conseguenza, nacque un problema: solo una classe base per gerarchia, ma per diversi aspetti comportamentali era necessaria la composizione. È stato necessario cambiare l'architettura in interfacce.
Storia
Il team tentava di ereditare due classi astratte (una con logica, l'altra con utilità comuni), il che è impossibile in Kotlin. Il problema è emerso già nella fase di estensione dell'applicazione. Questo ha portato a un significativo debito tecnico, poiché le classi dovevano essere riorganizzate in fretta.