[Kotlin] Enum Class VS Sealed Class

1

안녕하세요 오늘은 Enum ClassSealed Class의 차이를 알아보고자 합니다.
일단 예제를 보고, 둘의 차이를 알아봅시다.
저희는 커피장사를 하기로 했고, 커피메뉴를 EnumClass로 정의를 했습니다.

Enum Class

enum class CafeMenu(val price: Int) {
    //커피
    COFFEE(1000),
    LATTE(1500),
    //밀크티
    MEALKTEA(2000),

    //초코티!
    CHOCOTEA(3000)
}
// 대충 아래와 같이 주문하고 받습니다.
fun main() {
    val 손님 = `손님`(30000)
    val 주방장 = `주방장`(0)

    val menu = 손님.`주문을 하다`(CafeMenu.CHOCOTEA)
    주방장.`주문을 받다`(menu)

}

class `손님`(var money: Int) {

    fun `주문을 하다`(cafeMenu: CafeMenu): CafeMenu {
        money -= cafeMenu.price
        return cafeMenu
    }
}

class `주방장`(var money: Int) {

    fun `주문을 받다`(cafeMenu: CafeMenu): CafeMenu {
        money += cafeMenu.price
        return `음료를 제공하다`(cafeMenu)
    }

    private fun `음료를 제공하다`(cafeMenu: CafeMenu): CafeMenu = cafeMenu
}

근데 어느날 저희는 항상 3가지메뉴만 팔고있었는데, 장사가 너무 잘되서 따뜻한것과 차가운것을 구분해서 팔기로 했습니다.
거기에, 커피와 라떼는 디카페인을 추가하기로 했습니다.
여기서 문제가 시작됩니다.

enum class CafeMenu(val price: Int, val temperature: Temperature) {
    //커피                           
    COFFEE(1000 , Temperature.HOT, isDecaffein = false), //에러
    LATTE(1500, Temperature.ICE, isDecaffein = false), //에러
    //밀크티
    MEALKTEA(2000, Temperature.ICE),

    //초코티!
    CHOCOTEA(3000, Temperature.ICE)
}

enum class Temperature {
    ICE,
    HOT
}


fun main() {
    val 손님 = `손님`(30000)
    val 주방장 = `주방장`(0)

    val menu = 손님.`주문을 하다`(CafeMenu.CHOCOTEA(temperature = Temperature.ICE)) //에러
    주방장.`주문을 받다`(menu)

}

enumClass는 클래스이지만 선언과 동시에 생성자를 호출하고, 내부의 값을 변경할 수 없다는 특징을 갖고 있습니다.
또한 COFFEELATTE에게만 별도의 property를 만들지 못합니다.

  • Enum Class는 클래스이며, 내부의 값을 변경하지 못한다.
  • Enum Class는 별도의 인자를 만들지 못하며, 공통인자만 만들수 있다.

Java에서는 이걸 abstract class를 통해 해결할 수 있었습니다.

abstract class CafeMenu123( price : Int, temperature: Temperature )

data class COFFEE123(val price: Int, val temperature: Temperature) : CafeMenu123(price, temperature)

data class MEALKTEA123(val price: Int, val temperature: Temperature, val isDecaffein : Boolean) : CafeMenu123(price, temperature)

하지만 문제는 컴파일단에서 얼마나 상속하고있는지 알수가 없기때문에 ,enum class처럼 When일때 else를 생략할 수 없었습니다.

그래서 젯브레인 행님들은 생각했습니다.

그러면 제한을 걸어서 컴파일러가 알게끔 만들면 어떨까??

이리하여 sealed class가 만들어 졌습니다.

Sealed Class

sealed Classabstract class를, sealed Interfaceinterface라고 생각하시면 됩니다.

abstract classinterface다른점이 있다면, 타입을 제한하고 있기 때문에when을 사용할때 else없이도 사용이 가능합니다.
이러한 내용은 아까전에 말했기 때문에 생략하도록 하겠습니다.

sealed class CafeMenu(open val price: Int, open val temperature: Temperature) {

    //커피
    data class COFFEE(override val price: Int, override val temperature: Temperature) : CafeMenu(price, temperature)
    data class LATTE(override val price: Int, override val temperature: Temperature) : CafeMenu(price, temperature)

    //밀크티
    data class MEALKTEA(override val price: Int, override val temperature: Temperature, val isDecaffein: Boolean) :
        CafeMenu(price, temperature)

    //초코티!
    data class CHOCOTEA(override val price: Int, override val temperature: Temperature, val isDecaffein: Boolean) :
        CafeMenu(price, temperature)
}

enum class Temperature {
    ICE,
    HOT
}


fun main() {
    val 손님 = `손님`(30000)
    val 주방장 = `주방장`(0)
    val menu = 손님.`주문을 하다`(CafeMenu.CHOCOTEA(1000 , Temperature.ICE , isDecaffein = false))
    주방장.`주문을 받다`(menu)

}

그럼 Enum Class는 언제 사용할까?

enum 클래스의 장점은 즉시 직렬화 및 역직렬화할 수 있다는 것입니다.
또한 values()valueOf, enumValues 같은 함수를 사용하여 유형별로 열거형 값을 얻을 수 있습니다.

ICE나 HOT 같은 단순한 상수(변하지 않는값) 의 경우에는 Enum Class를 사용하고, 상태가 들어가고자 한다면 sealed class 를 사용하는게 올바르지 않을까 생각됩니다.

읽어 주셔서 감사합니다! <3


참고

코틀린 sealed class vs enum class | 공통점 과 차이점
[Kotlin] Enum의 대체 - Sealed class / Sealed interface 정리

profile
쉽게 가르칠수 있도록 노력하자

0개의 댓글