10. Data, Enum, Sealed Classes

다양한 클래스

치트시트

  • Data class

    • 자동 생성: equals/hashCode/toString/copy

    • 서버 DTO, 값 객체에 사용

  • Enum class

    • 제한된 상수, when과 함께 활용

    • 권한/상태/타입 상수에 적합

  • Sealed class

    • 제한된 계층, 상태 모델링

    • Enum보다 유연, 각 상태마다 데이터/로직 포함 가능

    • API 응답, 오류 처리, 상태 전이 모델링


1) Data Class — DTO와 값 객체(Value Object) 최적화

  • data 키워드로 선언

  • 자동 생성: equals, hashCode, toString, copy, componentN

data class UserDto(
    val id: Long,
    val name: String,
    val email: String?
)
  • 서버 활용 패턴

    • API DTO (요청/응답)

    • JPA Entity와 구분된 전송 객체

    • 도메인 모델의 값 객체 (예: Money, Email)

👉 자바에서는 Lombok이나 record(JDK16+)로 비슷한 효과를 냈지만, 코틀린은 언어 차원에서 기본 제공


2) Enum Class — 제한된 상수 집합

  • 자바 Enum과 동일하지만, when과 함께 강력해짐

enum class Role { ADMIN, USER, GUEST }

fun authorize(role: Role) = when(role) {
    Role.ADMIN -> "full access"
    Role.USER -> "limited"
    Role.GUEST -> "readonly"
}
  • 특징:

    • 상속 불가, 인터페이스 구현 가능

    • 각 인스턴스는 싱글톤

  • 서버 활용 패턴

    • 권한(Role), 상태(Status), 타입(Type) 상수 표현

    • DB 매핑 시 문자열/숫자 Enum과 매핑


3) Sealed Class — 상태 표현과 제한된 계층

  • sealed 키워드로 선언

  • 같은 파일/패키지 내에서만 하위 클래스 선언 가능

  • 컴파일 타임에 모든 하위 타입을 알고 있음

sealed class ApiResult {
    data class Success(val data: Any): ApiResult()
    data class Error(val message: String): ApiResult()
    object Loading: ApiResult()
}

fun handle(result: ApiResult) = when(result) {
    is ApiResult.Success -> println("ok: ${result.data}")
    is ApiResult.Error -> println("error: ${result.message}")
    ApiResult.Loading -> println("loading")
}
  • Enum vs Sealed

    • Enum: 값 자체만 구분, 고정된 상수

    • Sealed: 각 상태마다 데이터/로직 포함 가능

  • 서버 활용 패턴

    • API 응답 래퍼 (성공/실패/로딩)

    • 비즈니스 로직 상태 모델링 (예: 결제 진행 단계, 인증 단계)

    • 오류 처리 (Success/Failure/Retry 같은 타입 안전 표현)

👉 자바도 JDK17부터 sealed class 도입


4) 실무 예시 (서버 개발)

A. 서비스 계층 응답

sealed class ServiceResult<out T> {
    data class Ok<T>(val value: T): ServiceResult<T>()
    data class Fail(val reason: String): ServiceResult<Nothing>()
}

fun findUser(id: Long): ServiceResult<UserDto> =
    repo.find(id)?.let { ServiceResult.Ok(it) }
        ?: ServiceResult.Fail("Not found")

B. 도메인 값 객체

data class Money(val amount: Long) {
    init { require(amount >= 0) }
}

C. 권한 정의

enum class Permission { READ, WRITE, DELETE }

Last updated