← Назад к вопросам

Какие знаешь ограничения у sealed class?

1.7 Middle🔥 81 комментариев
#Kotlin основы#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ограничения 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.

Какие знаешь ограничения у sealed class? | PrepBro