안녕하세요 오늘은 Enum Class와 Sealed Class의 차이를 알아보고자 합니다.
일단 예제를 보고, 둘의 차이를 알아봅시다.
저희는 커피장사를 하기로 했고, 커피메뉴를 EnumClass로 정의를 했습니다.
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는 클래스이지만 선언과 동시에 생성자를 호출하고, 내부의 값을 변경할 수 없다는 특징을 갖고 있습니다.
또한 COFFEE와 LATTE에게만 별도의 property를 만들지 못합니다.
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
는 abstract class
를, sealed Interface
는 interface
라고 생각하시면 됩니다.
abstract class
나 interface
다른점이 있다면, 타입을 제한하고 있기 때문에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 클래스의 장점은 즉시 직렬화 및 역직렬화할 수 있다는 것입니다.
또한 values()
과 valueOf
, enumValues
같은 함수를 사용하여 유형별로 열거형 값을 얻을 수 있습니다.
ICE나 HOT
같은 단순한 상수(변하지 않는값) 의 경우에는 Enum Class를 사용하고, 상태가 들어가고자 한다면 sealed class
를 사용하는게 올바르지 않을까 생각됩니다.
읽어 주셔서 감사합니다! <3
코틀린 sealed class vs enum class | 공통점 과 차이점
[Kotlin] Enum의 대체 - Sealed class / Sealed interface 정리