Sealed Class — un tip special de clasă în Kotlin care limitează ierarhia de moștenire la un set fix de subtipuri. Toți moștenitorii sunt declarați în același fișier și sunt cunoscuți de compilator, ceea ce permite utilizarea unui bloc when exhaustiv fără o ramură else obligatorie. Potrivit Kotlin Docs, 2026, clasele sigilate sunt mecanismul cheie pentru reprezentarea ierarhiilor limitate, cum ar fi stările, tipurile de erori și evenimentele UI.
Principalele aspecte
Sealed Class (clasă sigilată) — este o clasă în Kotlin marcată cu modificatorul sealed. Ea definește o ierarhie limitată de tipuri: toți moștenitorii posibili sunt enumerați în același fișier, iar compilatorul știe despre fiecare dintre ei. Aceasta deosebește sealed class de o clasă deschisă obișnuită, ai cărei moștenitori pot fi declarați oriunde.
Scopul principal al sealed class este reprezentarea tip-securizată a unui set finit de variante. Fiecare moștenitor poate avea propria structură de date, ceea ce face sealed class mai flexibil decât enum. La runtime, sealed class este o clasă abstractă obișnuită, compilatorul impunând restricții doar în faza de compilare.
Sealed class este deosebit de util în arhitectura Android a aplicațiilor: stări UI, rezultate ale cererilor de rețea, evenimente de navigare de tip Intent și, desigur, ierarhii de erori — scenarii tipice de aplicare.
La compilare, sealed class este optimizat într-un tabel de tranziții pentru expresiile when, ceea ce îl face mai performant decât lanțurile if-else. În combinație cu data class, fiecare moștenitor poate conține nu doar stare, ci și metode, permițând construirea de modele de domeniu auto-documentate fără cod boilerplate.
Sealed class este eficient și pentru reprezentarea automatelor finite (state machine) în aplicațiile mobile. Fiecare stare — un moștenitor separat cu parametri unici, iar tranzițiile între stări sunt controlate prin expresia when. Compilatorul garantează că toate stările posibile au fost procesate, ceea ce elimină erorile de runtime la modificarea stării UI sau a logicii de business.
Dezvoltatorii începători în Kotlin confundă adesea sealed class cu enum, deoarece ambele limitează setul de valori. Însă există o diferență fundamentală între ele: enum — este un set de constante de același tip, sealed class — o ierarhie de tipuri diferite.
Enum este optim atunci când toate variantele sunt constante fără structură suplimentară. De exemplu, zilele săptămânii, stările comenzii sau tipurile de acțiuni fără parametri. Fiecare valoare enum este un singleton cu un nume fix.
Sealed class este necesar atunci când fiecare variantă are propriile date. De exemplu, o eroare de rețea conține codul de răspuns, o eroare de parsare — detalii, iar o eroare de autorizare — un mesaj. Fiecare moștenitor al sealed class este un tip separat cu câmpuri unice.
// Enum — toate variantele unui singur tip
enum class Status { LOADING, SUCCESS, ERROR }
// Sealed class — fiecare variantă cu propriile date
sealed class UiState<out T> {
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String) : UiState<Nothing>()
}
Începând cu Kotlin 1.5, există posibilitatea de a declara sealed interface. Aceasta extinde conceptul sealed la interfețe: sealed interface are de asemenea un set fix de implementări, dar suportă moștenirea multiplă.
Sealed interface este convenabil atunci când moștenitorii trebuie să implementeze mai multe contracte simultan. De exemplu, un eveniment UI poate fi simultan clickabil și urmăribil. Cu sealed class ar trebui să alegeți o singură clasă de bază, cu sealed interface moștenitorul le implementează pe ambele.
Sealed class este o clasă, deci fiecare moștenitor poate avea doar un părinte. Sealed interface rezolvă această problemă, dar nu poate conține stare. Alegerea dintre ele depinde de sarcină: aveți nevoie de logică comună cu câmpuri — sealed class, aveți nevoie de flexibilitate a contractelor — sealed interface.
sealed interface ScreenEvent {
data class Refresh(val force: Boolean) : ScreenEvent
data class Navigate(val route: String) : ScreenEvent
data class ShowError(val toast: String) : ScreenEvent
}
sealed interface AnalyticsEvent {
val name: String
val params: Map<String, Any>
}
// Moștenitorul implementează ambele interfețe
data class LoginClicked(
override val name: String = "login_click",
override val params: Map<String, Any> = emptyMap()
) : ScreenEvent, AnalyticsEvent
Una dintre principalele utilizări ale sealed class în dezvoltarea mobilă — ierarhia tip-securizată a erorilor. În loc să aruncați excepții de diferite tipuri sau să utilizați Exception generic, sealed class colectează toate erorile posibile de domeniu într-un singur tip.
Creați un sealed class DomainError și enumerați toate tipurile de defecțiuni ca moștenitori. Fiecare moștenitor conține doar datele care au sens pentru acel tip de eroare. Compilatorul garantează că la procesarea erorii nu veți uita nici o variantă.
Să considerăm o aplicație cu autentificare, unde sunt posibile diferite scenarii de defecțiune: parolă incorectă, blocarea contului, problemă cu serverul. Sealed class le unește într-un singur tip cu gestionare exhaustivă.
sealed class AuthError {
data class InvalidCredentials(
val attempts: Int
) : AuthError()
data class AccountBlocked(
val until: Long
) : AuthError()
data class NetworkFailure(
val cause: Throwable
) : AuthError()
object ServerError : AuthError()
}
fun handleError(error: AuthError): String = when (error) {
is AuthError.InvalidCredentials ->
"Au rămas încercări: ${3 - error.attempts}"
is AuthError.AccountBlocked ->
"Acces blocat până la ${Date(error.until)}"
is AuthError.NetworkFailure ->
"Verificați conexiunea: ${error.cause.localizedMessage}"
AuthError.ServerError ->
"Serverul este temporar indisponibil"
}
Sealed class a devenit un instrument standard în arhitectura aplicațiilor Android. Să examinăm trei modele cheie în care sealed class este de neînlocuit în dezvoltarea mobilă.
Separat, merită menționată aplicarea sealed class în Clean Architecture. Fiecare strat (data, domain, presentation) utilizează sealed class pentru propriile tipuri de erori, iar mapperii transformă un sealed class în altul. De exemplu, DataError din stratul de date este mapat în DomainError pentru logica de business, apoi în UiState pentru stratul de prezentare. Aceasta păstrează tip-securitatea la toate nivelurile aplicației și garantează că nici o eroare nu rămâne neprocesată.
Testarea sealed class necesită o abordare specială, deoarece fiecare moștenitor este un tip separat cu propria stare. Se recomandă scrierea de teste parametrizate care parcurg toți moștenitorii sealed class. Aceasta garantează că expresiile when acoperă toate variantele, inclusiv pe cele noi adăugate la extinderea ierarhiei.
Pentru testele UI, sealed class ca UiState permite verificarea afișării fiecărei stări: Loading arată un spinner, Content — date, Error — un mesaj de eroare. Deoarece sealed class este finit, acoperirea testelor pentru toate stările oferă încredere completă în corectitudinea logicii UI.
În ciuda simplității conceptului, dezvoltătorii fac frecvent greșeli la proiectarea ierarhiilor sealed class. Să examinăm principalele probleme și modalitățile de a le evita.
Întrebări frecvente
Da, sealed class poate conține metode abstracte, iar fiecare moștenitor este obligat să le implementeze. Este convenabil când toate variantele trebuie să ofere o interfață comună, dar cu logică de execuție diferită.
În Java 17+ au apărut clase și interfețe sigilate cu modificatorul sealed. Android suportă parțial Java 17 deocamdată, dar în proiectele Kotlin sealed class este disponibil din Kotlin 1.0 fără restricții.
Da, un sealed class poate fi moștenitorul altuia. Ierarhia sealed class rămâne finită: compilatorul cunoaște toți moștenitorii la fiecare nivel. Aceasta permite construirea de clasificări detaliate ale erorilor.
Sealed class nu creează cheltuieli suplimentare la runtime. Compilatorul optimizează expresiile when cu sealed class în tabele de tranziție (tableswitch), ceea ce este mai rapid decât lanțurile if-else. Performanța este identică cu enum.
Fiecare moștenitor al sealed class se testează separat. Deoarece sealed class este finit, se poate scrie un test parametrizat care parcurge toate variantele. Aceasta oferă acoperire completă a ramurilor blocurilor when.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și