Sealed Classes와 제한된 계층 구조(Restricted Hierarchies)
Sealed Classes와 제한된 계층 구조(Restricted Hierarchies)
코틀린의 sealed class는 컴파일 타임에 모든 서브타입이 확정되는 닫힌 집합(closed set)을 정의하며, 컴파일러가 패턴 매칭에서 가능한 모든 케이스를 처리했는지 검증할 수 있도록 합니다. 일반적인 open class와 달리 어떤 모듈에서든 새로운 서브클래스를 추가할 수 있는 것이 아니라, sealed class는 직접 서브클래스를 동일 패키지 내로 제한하여 컴파일러가 계층 구조를 완전히 파악할 수 있게 합니다. 이러한 특성 덕분에 sealed class는 유한한 상태(finite state), 결과 타입(result type), 프로토콜 메시지 등을 모델링하는 데 핵심적인 역할을 합니다. 실제 안드로이드 프로젝트에서 UI 상태 관리, 네트워크 응답 처리, 내비게이션 이벤트 디스패치 등 다양한 영역에서 sealed class를 활용하는 패턴은 면접에서도 빈번하게 등장하므로, 그 원리와 활용법을 확실히 이해해 두시는 것이 중요합니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
sealed class가 서브클래스 정의를 어떻게 제한하며, 이것이 완전성 검사(exhaustiveness checking)에 왜 중요한지 설명할 수 있습니다.when식이 모든 sealed 서브타입을 처리할 때 컴파일러가 어떻게 동작하는지 이해할 수 있습니다.sealed class,sealed interface,enum class를 제한된 타입 모델링 관점에서 비교할 수 있습니다.sealed class가 타입 안전성을 높여 주는 대표적인 패턴을 파악할 수 있습니다.- UI 상태, 네트워크 결과, 내비게이션 이벤트 등을 sealed 계층 구조로 모델링하는 방법을 적용할 수 있습니다.
서브클래스 제한과 완전성 검사(Exhaustiveness)
sealed class는 모든 직접 서브클래스가 자신과 동일한 패키지 내에서 정의되어야 합니다. Kotlin 1.5부터는 같은 파일에 있지 않아도 되지만, 반드시 같은 패키지를 공유해야 합니다. 이 제약 조건 덕분에 컴파일러는 모든 사용 지점에서 가능한 서브타입 목록을 완전히 파악할 수 있습니다.
sealed class NetworkResult {
data class Success(val data: String) : NetworkResult()
data class Error(val message: String) : NetworkResult()
data object Loading : NetworkResult()
}
sealed class를 when 식에서 사용하여 모든 서브타입을 처리하면, 컴파일러는 해당 매칭이 완전(exhaustive)하다는 것을 인지합니다. 따라서 else 분기가 필요 없으며, 이후에 새로운 서브타입을 추가하면 해당 서브타입을 처리하지 않은 모든 when 사용 지점에서 컴파일 오류가 발생합니다.
fun render(result: NetworkResult) = when (result) {
is NetworkResult.Success -> showData(result.data)
is NetworkResult.Error -> showError(result.message)
NetworkResult.Loading -> showSpinner()
// else 분기 불필요: 컴파일러가 모든 케이스를 검증합니다
}
처리되지 않은 케이스에서 발생하는 컴파일 타임 오류야말로 open class 계층 구조 대비 가장 큰 장점입니다. open class의 경우 알 수 없는 서브타입이 존재할 가능성이 있으므로 컴파일러는 반드시 else 분기를 요구합니다. 반면 sealed class를 사용하면 컴파일러가 이러한 불확실성을 완전히 제거할 수 있습니다. 면접에서 이 차이점을 명확히 설명할 수 있다면, sealed class의 핵심 가치를 이해하고 있다는 것을 보여줄 수 있습니다.
Sealed Classes vs Enum Classes
enum class도 완전성 검사를 제공하지만, sealed class와는 두 가지 중요한 차이점이 있습니다. 첫째, 각 enum 상수는 싱글톤입니다. 동일한 enum 값에 대해 서로 다른 데이터를 가진 두 개의 인스턴스를 만들 수 없습니다. 반면, sealed class의 서브타입은 자체 생성자와 상태를 가진 일반 클래스가 될 수 있습니다.