Какие знаешь ограничения у sealed class?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ограничения Sealed Class в Kotlin
Sealed Class — это мощный инструмент для представления ограниченных иерархий наследования. Однако у него есть важные ограничения, которые нужно учитывать.
Что такое Sealed Class
Sealed Class — это абстрактный класс, все возможные подклассы которого известны на этапе компиляции:
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}
Ограничения Sealed Class
1. Все подклассы должны быть определены в одном файле/пакете
До Kotlin 1.1 подклассы должны были быть вложенными. Теперь они могут быть в одном пакете, но это всё равно ограничение:
// Правильно
sealed class Result<T>
class Success<T>(val data: T) : Result<T>()
class Error(val e: Exception) : Result<Nothing>()
// Нельзя наследовать из другого пакета
// package com.other
// class CustomResult : Result<String>() // ОШИБКА!
2. Не может быть открытым для расширения
Sealed class автоматически абстрактный и финальный, что ограничивает его использование:
sealed class Animal // автоматически abstract
class Dog : Animal() // OK
class Cat : Animal() // OK
open class Bird : Animal() // ОШИБКА! Нельзя открыть для наследования
3. Прямые подклассы должны быть конкретными классами
Чтобы создавать подклассы, нужны конкретные классы или object:
sealed class HttpResponse
data class Success(val body: String) : HttpResponse()
object Timeout : HttpResponse()
class Custom : HttpResponse() // OK
// abstract class Abstract : HttpResponse() // ОШИБКА!
4. Могут быть только в определённом месте
Вложенные sealed классы могут быть в других пакетах, но только через наследование в одном месте:
sealed class ViewState {
object Loading : ViewState()
data class Content(val data: String) : ViewState()
data class Error(val message: String) : ViewState()
}
// Подклассы могут быть добавлены только в этом файле или в том же пакете
5. Конструктор приватный по умолчанию
Конструктор sealed class по умолчанию приватный:
sealed class Base(val value: Int) // конструктор приватный
class Child(val name: String) : Base(42) // OK
// val base = Base(10) // ОШИБКА! Конструктор приватный
Практическое применение
Sealed class идеально подходит для представления ограниченного набора типов:
sealed class UiEvent {
data class ButtonClicked(val buttonId: Int) : UiEvent()
data class TextChanged(val text: String) : UiEvent()
object ScreenClosing : UiEvent()
}
fun handleEvent(event: UiEvent) = when(event) {
is UiEvent.ButtonClicked -> println("Button ${event.buttonId} clicked")
is UiEvent.TextChanged -> println("Text: ${event.text}")
UiEvent.ScreenClosing -> println("Closing")
// Compiler гарантирует, что все случаи обработаны!
}
Альтернативы
Enum class — если все значения известны и фиксированы:
enum class Status { LOADING, SUCCESS, ERROR }
Interface — если нужна больше гибкости в наследовании
Regular abstract class — если нужны подклассы в разных пакетах
Итоги
Sealed class — это отличный инструмент для типобезопасного представления ограниченных иерархий. Его ограничения — это не баги, а фичи, которые помогают компилятору гарантировать полноту обработки всех возможных типов в pattern matching.