Developing Myself Everyday

Kotlin은 코드의 생산성과 가독성을 향상시키기 위해 설계된 정적 타입 언어입니다. 이 언어는 개발 프로세스를 단순화하는 여러 기능을 제공하며, 그 중에서도 sealed classenum class가 있습니다.

 

이 두 종류의 클래스는 서로 다른 목적을 가지며 다른 시나리오에서 사용될 수 있습니다. 이 글에서는 Kotlin에서 sealed class enum class의 차이점 및 코드의 디자인과 구현을 개선하는 데 어떻게 활용할 수 있는지 탐색해보겠습니다.


 

sealed class와 enum class의 차이


아래는 발생할 수 있는 HTTP 오류를 sealed class enum class로 표현한 코드입니다. 두 개의 클래스 모두 2개의 HTTP 오류를 가지고 있으며 `code` 프로퍼티를 통해 오류 코드를 저장합니다.

sealed class HttpError(val code: Int) {
    object Unauthorized: HttpError(401)
    object NotFound: HttpError(404)
}

enum class EnumHttpError(val code: Int) {
    Unauthorized(401),
    NotFound(404)
}

 

 

위 2개의 클래스는 동일하게 수행하는 것처럼 보입니다. 한 번 위 2개의 클래스를 사용해 보겠습니다.

val error: HttpError = HttpError.NotFound
when(error) {
    HttpError.Unauthorized -> Unit
    HttpError.NotFound -> Unit
}

val enumError: EnumHttpError = EnumHttpError.NotFound
when(enumError) {
    EnumHttpError.Unauthorized -> Unit
    EnumHttpError.NotFound -> Unit
}

처리할 때도 차이가 거의 없습니다. 두개의 클래스 모두 else문을 생략할 수 있습니다.

 

 

그렇다면?

그럼 sealed class enum class의 가장 큰 차이점은 무엇일까요? 

 

바로 enum class는 실제 상수를 처리하고 sealed class에서는 개별 인스턴스를 처리한다는 것입니다.

 

이를 설명하기 위해 sealed class를 조금 바꿔 보겠습니다. 우리는 Unauthorized 오류가 발생했을 때 그 이유를 알고 싶습니다. 그렇기에 `reason`이란 데이터를 추가하려고 합니다.

sealed class HttpError(val code: Int) {
    data class Unauthorized(val reason: String): HttpError(401)
    object NotFound: HttpError(404)
}

이전에는 HTTP 오류에 대한 추가 정보를 저장하지 않았기 때문에 각 오류를 싱글톤 객체로 표현하는 것이 합리적이었습니다. 그런데 `reason`이라는 추가 데이터를 저장하고자 할 때, Unauthorized 오류의 경우 `reason`을 저장하기 위해 데이터 클래스로 선언하는 것이 적절합니다.

 

이제 `reason` 필드를 가지고 있으므로 Unauthorized 오류는 서로 다른 `reason` 값을 가진 여러 인스턴스를 생성할 수 있어야 합니다. 이러한 경우에는 데이터 클래스가 사용될 수 있습니다. 따라서 코드의 수정이 필요하며, 이렇게 수정하면 Unauthorized 클래스의 인스턴스는 `reason` 필드의 값에 따라 달라질 수 있게 됩니다.

 

이런 기능 덕분에 sealed class는 자유도가 매우 높아 사용자의 입맛대로 클래스를 만들 수 있습니다.

 


enum class는 이와같이 사용자 정의 가능성을 제공하지 않습니다. 그렇기에 우리는 sealed class를 사용해야 합니다.

 

 

 

enum class를 사용해야 할 경우

만약 생성자에는 변수만 있고 하위 클래스 중 어느 것도 개별 동작이 필요하지 않은 경우에는 enum class를 사용할만한 이유가 존재합니다.

 

바로 enum class상수 값이 컴파일 타임에 알려지기 때문에 가능한 모든 값을 제공받을 수 있다는 점입니다.

 

바로 `values()`를 사용하면 enum class의 가능한 값의 배열을 얻을 수 있습니다.

val values: Array<EnumHttpError> = EnumHttpError.values()

 

추가로 1.8.20에서 experimental로 추가되었던 enum class `entries` 속성이 stable로 변경되었습니다. 기존 `values()`를 대체하는 속성으로 일단 가지고 있는 원소를 모두 list 형태로 반환해 주기 때문에 성능이나 활용면에서 훨신 편해 졌습니다.

val list: List<EnumHttpError> = EnumHttpError.entries

 

sealed class에서는 이게 힘들기에 이런 상황에서 enum class를 사용하는 것이 좋습니다.

 

profile

Developing Myself Everyday

@배준형

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!