[Spring/Kotlin] Sealed Class로 DTO 생성하기

easyone·2026년 6월 21일

Spring

목록 보기
25/25

Kotlin Sealed Class

sealed class는 상속 가능한 범위를 같은 파일로 제한하는 클래스다.

sealed class Shape
data class Circle(val radius: Double) : Shape()
data class Rectangle(val w: Double, val h: Double) : Shape()

컴파일러가 모든 하위 타입을 알고 있기 때문에, when 분기에서 else 없이도 모든 케이스를 강제 처리할 수 있다.

when (shape) {
    is Circle -> ...
    is Rectangle -> ...
    // else 불필요 — 누락 시 컴파일 에러
}

나중에 Triangle을 추가하면, 처리하지 않은 when에서 즉시 컴파일 에러가 발생한다. 런타임이 아닌 컴파일 타임에 누락을 잡아주는 게 핵심.


언제 쓰는지?

타입에 따라 가지고 있는 데이터 구조가 다를 때 유용하다.


실제 사용 예 — 타임라인 API 응답 DTO

요구사항

타임라인 아이템은 식사 기록이 1개인 SINGLE과 2개 이상인 GROUP 두 가지 타입이 있다. 문제는 등급(grade) 필드가 SINGLE일 때만 존재한다는 점이다. 또한 여러개이려면 대표 음식도 두개를 표시해야 한다. 그리고 같이 기록된 음식의 개수도 표시해야 한다.

이걸 하나의 DTO로 표현하면 이렇게 된다.

data class TimeLineItemDTO(
    val type: TimeLineType,
    val grade: String?,  // SINGLE이면 값 있고, GROUP이면 null
    ...
)

grade가 null인 이유가 타입 레벨에서 드러나지 않는다. 클라이언트는 왜 null인지 알 수 없고, 서버도 grade를 실수로 채워 보내도 컴파일러가 잡아주지 못한다. 즉 타입에 따라 해당하지 않는 필드를 null로 채우면 비효율적이라는 것이다.

sealed class로 분리하면 이 문제가 사라진다.

sealed class TimeLineItemDTO {
    data class Single(
        val grade: String,  // non-null 보장
        ...
    ) : TimeLineItemDTO()

    data class Group(
        // grade 자체가 없음
        ...
    ) : TimeLineItemDTO()
}

SINGLE이면 grade가 반드시 있고, GROUP이면 애초에 필드가 없다. nullable 대신 타입 구조로 제약을 표현한 것이다. 서비스 레이어에서 when 분기로 각 타입을 생성하면 컴파일러가 모든 케이스 처리를 강제한다.


abstract class와 비슷하지만 상속 범위 제한 + 분기 누락 검사 가 추가된 것으로 이해하면 된다.

abstract class는 누군가 다른 파일에서 Triangle : Shape()를 추가할 수도 있으니, 컴파일러는 when에 무조건 else를 강제한다. 즉 해당 요구사항에서는 두 타입만 올것인데 다른게 올 수 있다고 하는 것이다.

sealed class는 하위 타입을 전부 안다는 것이 보장되니까, when에서 모든 케이스를 빠짐없이 처리했는지를 컴파일러가 검사해줄 수 있다.
만약 Triangle을 새로 추가했는데 when에서 빼먹으면, 그 즉시 컴파일 에러가 난다는 점에서 abstract class와 차이가 있다.

profile
백엔드 개발자 지망 대학생

1개의 댓글

comment-user-thumbnail
2026년 6월 27일

sealed class와 enum class가 넘모 좋아요오~~

답글 달기