sealed class в Kotlin — это абстрактный класс, ограничивающий иерархию наследников: все подтипы должны быть объявлены в одном файле. Это удобно для иерархий, где набор вариантов фиксирован (например, для описания состояний, событий или ошибок):
sealed class Result { object Success : Result() data class Error(val message: String) : Result() object Loading : Result() } fun handle(result: Result) = when (result) { is Result.Success -> print("Success!") is Result.Error -> println("Error: ${result.message}") is Result.Loading -> println("Loading...") }
Связь с when:
Если мы используем все подтипы sealed class в when-выражении, то компилятор проверяет exhaustiveness (исчерпывающий разбор вариантов). Это гарантирует, что при добавлении нового состояния разработчик получит ошибку компиляции, если не обработает новый вариант.
Зачем это нужно:
"Можно ли располагать наследников sealed class в разных файлах или пакетах? Как это влияет на type-safety?"
Ответ: Нет, все прямые наследники sealed class должны быть определены в одном файле. Это контроль компилятора для гарантий type-safety. Если наследников разместить в других файлах пакета, компилятор выдаст ошибку.
История
При проектировании бизнес-логики платежей добавляли варианты результатов операции, забыв обновить when-выражение. Но благодаря sealed class, компилятор подсветил неучтённые случаи. В другом проекте на Java этот сценарий привёл бы к попаданию неинициализированного статуса в продукт.
История
В проекте после миграции части данных sealed class на обычные open class перестали работать exhaustive when-проверки — новые статусы начали "теряться" в логике обработки, что вызывало некорректное поведение интерфейса.
История
В e-commerce системе была попытка оптимизировать архитектуру через вынесение наследников sealed class в отдельные файлы (каждый — в свой модуль для переиспользования). Это сломало компиляцию и стало причиной экстренного рефакторинга перед релизом.