Sobes.tech
Middle

Qual è la differenza tra classi sealed e classi astratte in Kotlin?

sobes.tech AI

Risposta dell'AI

La principale differenza tra classi sealed e astratte è che le classi sealed limitano la gerarchia di ereditarietà all'interno di un singolo file o modulo (per Kotlin 1.5+). I discendenti di una classe sealed devono essere dichiarati nello stesso file della classe sealed stessa, garantendo un controllo esaustivo quando si usano le espressioni when.

Differenze:

  • Ereditarietà:
    • Le classi astratte possono essere ereditate ovunque nel progetto.
    • Le classi sealed possono essere ereditate solo all'interno dello stesso file (prima di Kotlin 1.5) o nello stesso modulo (con Kotlin 1.5+).
  • Utilizzo con when:
    • Quando si usa when con un tipo sealed, il compilatore può verificare che tutti i sottotipi possibili siano stati considerati, rendendo when esaustivo e eliminando la necessità di specificare esplicitamente un ramo else se tutti i sottotipi sono gestiti.
    • Con le classi astratte, il compilatore non può garantire l'esaustività, quindi spesso è necessario un else.
  • Creazione di istanze:
    • Né le classi astratte né quelle sealed possono essere istanziate direttamente.
  • Membri:
    • Sia le classi astratte che quelle sealed possono avere membri astratti e non astratti.

Esempio di classe sealed:

sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val message: String) : Result<Nothing>()
}

fun processResult(result: Result<Int>) {
    when (result) {
        is Result.Success -> {
            // Elaborazione del risultato di successo
            println("Successo: ${result.data}")
        }
        is Result.Error -> {
            // Gestione errore
            println("Errore: ${result.message}")
        }
        // Non è necessario else se tutti i sottotipi sono gestiti
    }
}

Esempio di classe astratta:

abstract class Shape {
    abstract fun area(): Double
}

class Circle(val radius: Double) : Shape() {
    override fun area(): Double = Math.PI * radius * radius
}

class Rectangle(val width: Double, val height: Double) : Shape() {
    override fun area(): Double = width * height
}

fun calculateArea(shape: Shape): Double {
    return shape.area()
}

Quando usarle:

  • Classi sealed: Ideali per rappresentare un insieme limitato di stati o tipi possibili, quando si necessita di una verifica esaustiva nelle espressioni when. Spesso usate per modellare risultati di operazioni (successo/errore), stati UI, eventi.
  • Classi astratte: Adatte per definire funzionalità e contratti generali per un gruppo di classi correlate, che possono essere ereditate ovunque nel progetto.

In sintesi, le classi sealed offrono un controllo più rigoroso sulla gerarchia di ereditarietà e migliorano la sicurezza e la leggibilità del codice quando si gestisce un insieme limitato di sottotipi.