Sealed Class — шта је то, принцип рада и примена

Аутор: IT Sectr Објављено: 2026-05-26 Време читања: 8 мин

Sealed Class — посебан тип класе у Kotlin-у који ограничава хијерархију наслеђивања на фиксни скуп подтипова. Сви наследници се декларишу у истом фајлу и познати су компајлеру, што омогућава коришћење исцрпног блока when без обавезне else гране. Према Kotlin Docs, 2026, запечаћене класе су кључни механизам за представљање ограничених хијерархија, као што су стања, типови грешака и UI догађаји.

Главно

  • Sealed Class — класа са фиксним скупом наследника, декларисаних у истом фајлу.
  • Exhaustive when — компајлер проверава да су сви подтипови обрађени, елиминишући заборављене else гране.
  • Sealed interface — Kotlin 1.5+ подржава запечаћене интерфејсе за вишеструко наслеђивање.
  • Хијерархија грешака — sealed class је стандардни начин типно-безбедне обраде грешака у Kotlin-у.
  • Разлика од enum — сваки наследник sealed class може садржати јединствено стање и различит број поља.

Шта је Sealed Class?

Sealed Class (запечаћена класа) — то је класа у Kotlin-у означена модификатором sealed. Она дефинише ограничену хијерархију типова: сви могући наследници су наведени у истом фајлу, и компајлер зна за сваког од њих. Ово разликује sealed class од обичне отворене класе, чији наследници могу бити декларисани било где.

Главна сврха sealed class-а је типно-безбедно представљање коначног скупа варијанти. Сваки наследник може имати сопствену структуру података, што чини sealed class флексибилнијим од enum. У рантајму, sealed class је обична апстрактна класа, компајлер намеће ограничења само у фази компајлирања.

Sealed class је посебно користан у архитектури Android апликација: UI стања, резултати мрежних захтева, Intent-слични догађаји навигације и, наравно, хијерархије грешака — типични сценарији примене.

При компајлирању, sealed class се оптимизује у табелу прелаза за when изразе, што га чини ефикаснијим од if-else ланаца. У комбинацији са data class, сваки наследник може садржати не само стање, већ и методе, што омогућава изградњу самодокументујућих доменских модела без boilerplate кода.

Sealed class је такође ефикасан за представљање коначних аутомата (state machine) у мобилним апликацијама. Свако стање — засебан наследник са јединственим параметрима, а прелази између стања се контролишу преко when израза. Компајлер гарантује да су сва могућа стања обрађена, што елиминише грешке у рантајму при промени UI стања или пословне логике.

Sealed Class и Enum: кључне разлике

Почетници у Kotlin-у често мешају sealed class са enum, јер оба ограничавају скуп вредности. Међутим, постоји суштинска разлика: enum — скуп константи истог типа, sealed class — хијерархија различитих типова.

Када изабрати enum

Enum је оптималан када су све варијанте константе без додатне структуре. На пример, дани у недељи, статуси поруџбине или типови акција без параметара. Свака enum вредност је singleton са фиксним именом.

Када изабрати sealed class

Sealed class је потребан када свака варијанта има сопствене податке. На пример, мрежна грешка садржи код одговора, грешка парсирања — детаље, а грешка ауторизације — поруку. Сваки наследник sealed class-а је засебан тип са јединственим пољима.

kotlin
// Enum — све варијанте једног типа
enum class Status { LOADING, SUCCESS, ERROR }

// Sealed class — свака варијанта са својим подацима
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>()
}

Sealed Interface против Sealed Class

Од Kotlin 1.5 постоји могућност декларисања sealed interface. Ово проширује концепт sealed на интерфејсе: sealed interface такође има фиксан скуп имплементација, али подржава вишеструко наслеђивање.

Када користити sealed interface

Sealed interface је згодан када наследници треба да имплементирају више уговора истовремено. На пример, UI догађај може бити истовремено кликабилан и следљив. Са sealed class требало би изабрати једну базну класу, са sealed interface наследник имплементира оба.

Ограничења sealed class

Sealed class је класа, па сваки наследник може имати само једног родитеља. Sealed interval решава овај проблем, али не може садржати стање. Избор између њих зависи од задатка: потребна је заједничка логика са пољима — sealed class, потребна је флексибилност уговора — sealed interface.

kotlin
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>
}

// Наследник имплементира оба интерфејса
data class LoginClicked(
    override val name: String = "login_click",
    override val params: Map<String, Any> = emptyMap()
) : ScreenEvent, AnalyticsEvent

Sealed Class за хијерархију грешака у мобилном развоју

Једна од главних примена sealed class-а у мобилном развоју — типно-безбедна хијерархија грешака. Уместо бацања изузетака различитих типова или коришћења општег Exception, sealed class прикупља све могуће грешке домена у један тип.

Како изградити хијерархију грешака

Креирајте sealed class DomainError и наведите све врсте отказа као наследнике. Сваки наследник садржи само оне податке који имају смисла за дати тип грешке. Компајлер гарантује да при обради грешке нећете заборавити ниједну варијанту.

Пример: обрада грешака аутентификације

Размотримо апликацију са ауторизацијом, где су могући различити сценарији отказа: погрешна лозинка, блокирање налога, проблем са сервером. Sealed class их обједињује у један тип са исцрпном обрадом.

kotlin
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 ->
        "Преостало покушаја: ${3 - error.attempts}"
    is AuthError.AccountBlocked ->
        "Приступ закључан до ${Date(error.until)}"
    is AuthError.NetworkFailure ->
        "Проверите везу: ${error.cause.localizedMessage}"
    AuthError.ServerError ->
        "Сервер је привремено недоступан"
}

Обрасци употребе Sealed Class у Android-у

Sealed class је постао стандардни алат у архитектури Android апликација. Размотримо три кључна обрасца где је sealed class незаменљив у мобилном развоју.

  • UI State — представљање екрана као коначног аутомата: Loading, Content, Error. Свако стање садржи своје податке, а sealed class гарантује да су сви прелази обрађени.
  • Navigation Event — sealed class уместо навигационих константи: сваки екран је засебан наследник са параметрима руте. Компајлер проверава типове аргумената.
  • Action/Intent — образац Unidirectional Data Flow користи sealed class за представљање свих радњи које корисник може извршити на екрану.

Посебно треба истаћи примену sealed class-а у Clean Architecture. Сваки слој (data, domain, presentation) користи sealed class за своје типове грешака, а мапери претварају један sealed class у други. На пример, DataError из слоја података се мапира у DomainError за пословну логику, а затим у UiState за презентациони слој. Ово чува типну безбедност на свим нивоима апликације и гарантује да ниједна грешка неће остати необрађена.

Тестирање sealed class хијерархија

Тестирање sealed class захтева посебан приступ, јер је сваки наследник засебан тип са сопственим стањем. Препоручује се писање параметризованих тестова који пролазе кроз све наследнике sealed class. Ово гарантује да when изрази покривају све варијанте, укључујући нове додате при проширењу хијерархије.

За UI тестове, sealed class као UiState омогућава проверу приказа сваког стања: Loading приказује спининг, Content — податке, Error — поруку о грешци. Пошто је sealed class коначан, тест покривеност свих стања даје пуну сигурност у исправност UI логике.

Типичне грешке при раду са Sealed Class

Упркос једноставности концепта, програмери редовно праве грешке при пројектовању sealed class хијерархија. Размотримо главне проблеме и начине да их избегнемо.

  • Наследници у различитим фајловима — компајлер неће дозволити декларисање sealed class ако су наследници ван фајла. Ово ограничење гарантује исцрпан when.
  • Мешање sealed и open — sealed class не може бити истовремено open. Ако је потребна проширива хијерархија, користите обичан abstract class, али ћете жртвовати исцрпност.
  • Претерано угнежђење — sealed class унутар sealed class ствара дубоку хијерархију коју је тешко одржавати. За једноставне сценарије довољна су два нивоа.
  • Заборављени else у when — ако sealed class из библиотеке нема исцрпност, компајлер неће упозорити о пропуштеној грани. Додајте else само свесно.

Често постављана питања

Може ли sealed class имати апстрактне методе?

Да, sealed class може садржати апстрактне методе, и сваки наследник их мора имплементирати. Ово је згодно када све варијанте треба да пруже јединствени интерфејс, али са различитом логиком извршења.

Да ли су sealed class доступни у Java?

У Java 17+ су се појавиле запечаћене класе и интерфејси са модификатором sealed. Android за сада делимично подржава Java 17, али у Kotlin пројектима sealed class је доступан од Kotlin 1.0 без ограничења.

Може ли sealed class наследити други sealed class?

Да, један sealed class може бити наследник другог. Хијерархија sealed class остаје коначна: компајлер зна све наследнике на сваком нивоу. Ово омогућава изградњу детаљних класификација грешака.

Да ли sealed class утиче на перформансе?

Sealed class не ствара додатне трошкове у рантајму. Компајлер оптимизује when изразе са sealed class у табеле прелаза (tableswitch), што је брже од if-else ланаца. Перформансе су идентичне са enum.

Како тестирати sealed class хијерархије?

Сваки наследник sealed class се тестира засебно. Пошто је sealed class коначан, можете написати параметризовани тест који пролази кроз све варијанте. Ово даје потпуну покривеност грана when блокова.

Закључци

  • Sealed class — класа са фиксним скупом наследника, декларисаних у једном фајлу, што даје исцрпну when анализу у фази компајлирања.
  • Сваки наследник sealed class може имати сопствену структуру података — главна разлика од enum, где су све варијанте константе истог типа.
  • Sealed interface (Kotlin 1.5+) подржава вишеструко наслеђивање, sealed class — само појединачно. Избор зависи од потребе за заједничким стањем.
  • Sealed class — стандардни механизам за типно-безбедну хијерархију грешака у Kotlin-у: сваки тип отказа — засебан наследник са релевантним пољима.
  • Главни обрасци у Android-у: UI State, Navigation Event и Action/Intent — изграђени на sealed class за гаранцију потпуности обраде.
  • Избегавајте наследнике у различитим фајловима, претерано угнежђење и мешање sealed са open — ово нарушава уговор коначне хијерархије.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође