sealed class vs enum, 언제 무엇을 써야 할까?

Kotlin에서 상태나 결과를 표현할 때 enumsealed 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()
}

이 경우 SuccessFailure

  • 같은 결과 범주에 속하지만
  • 담고 있는 데이터의 형태가 완전히 다르다

그래서 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 사이에서 흔들릴 일이 크게 줄어든다!!!

Leave a Comment