Kotlin에서 상태나 결과를 표현할 때 enum과 sealed class 사이에서 고민하는 경우가 많다.
두 타입은 겉보기엔 비슷해 보이지만, 의도와 쓰임새는 분명히 다르다.
핵심은 “값의 집합인가, 타입의 집합인가”다.
enum: 고정된 값의 집합
enum은 값이 미리 정해진 유한한 목록일 때 가장 적합하다.
특징
- 항목의 개수와 의미가 고정됨
- 모든 항목이 동일한 구조를 가짐
- 각 항목은 단순한 상수에 가까움
예시
enum class ExampleStatus {
READY,
RUNNING,
COMPLETED,
FAILED
}
이런 경우 ExampleStatus는
- 새로운 상태가 자주 추가되지 않고
- 각 상태가 추가 데이터를 필요로 하지 않으며
- “정해진 선택지 중 하나”라는 의미를 가질 때 적절하다.
when 문에서도 모든 케이스가 명확하게 드러난다.
when (status) {
ExampleStatus.READY -> { /* ... */ }
ExampleStatus.RUNNING -> { /* ... */ }
ExampleStatus.COMPLETED -> { /* ... */ }
ExampleStatus.FAILED -> { /* ... */ }
}
sealed class: 서로 다른 타입의 묶음
sealed class는 형태가 서로 다른 하위 타입들을 하나의 개념으로 묶고 싶을 때 사용한다.
특징
- 하위 타입마다 서로 다른 데이터 구조 가능
- 상태 자체가 하나의 “모델”이 됨
when에서 컴파일 타임에 exhaustiveness 보장
예시
sealed class ExampleResult {
data class Success(
val data: String
) : ExampleResult()
data class Failure(
val errorCode: Int,
val message: String
) : ExampleResult()
}
이 경우 Success와 Failure는
- 같은 결과 범주에 속하지만
- 담고 있는 데이터의 형태가 완전히 다르다
그래서 enum으로 표현하기엔 무리가 있다.
when (result) {
is ExampleResult.Success -> {
val value = result.data
}
is ExampleResult.Failure -> {
val reason = result.message
}
}
여기서 중요한 점은
각 상태가 단순한 값이 아니라, 의미 있는 타입이라는 것이다.
언제 enum을 쓰고, 언제 sealed class를 쓸까?
판단 기준을 간단히 정리하면 다음과 같다.
enum이 적합한 경우
- 값의 목록이 고정되어 있음
- 모든 항목이 같은 구조를 가짐
- 추가 데이터가 거의 필요 없음
sealed class가 적합한 경우
- 상태마다 필요한 데이터가 다름
- 성공/실패처럼 의미적으로 다른 모델을 표현해야 함
- 타입 안정성과 표현력을 중요하게 여길 때
한 줄 정리
- enum은 “고정된 값 집합”
- sealed class는 “타입이 다른 상태들의 묶음”
이 기준만 명확히 잡아두면,
모델링에서 enum과 sealed class 사이에서 흔들릴 일이 크게 줄어든다!!!