[Kotlin]Sealed Class란 무엇일까 ?

2024. 3. 22. 01:27·KOTLIN

👩‍💻 오늘의 할 일

오늘은 Kotlin의 Sealed Class에 대해 알아보겠습니다. 이전 동아리 면접 질문에서 Sealed Class와 Enum Class의 차이점을 물어봤는데 아예 몰라서 대답을 못했던 경험이 있어서 이 부분에 대해서도 한번 알아보고 가겠습니다. 멋사에서 Kotlin 수업을 들을 때 한 번 들었었는데 좀 더 자세히 알아보려고 합니다.

🔥 수업 시간에 배운 Sealed Class

  • Sealed Class는 자기 자신을 상속받은 클래스들을 모아 관리하는 개념입니다.
  • Kotlin의 클래스와 그 멤버 함수들은 final이기 때문에 상속될 수 없습니다.
  • sealed class는 그 자체로 추상적이기 때문에 open 키워드로 메서드를 상속할 수 있습니다
fun main() {
    val obj1 = NumberClass.OneClass(100, 200)
    val obj2 = NumberClass.TwoClass(300)
    val obj3 = NumberClass.ThreeClass(100, 11.11)

    checkNumber(obj1)
    checkNumber(obj2)
    checkNumber(obj3)
}

sealed class NumberClass{

    open fun numberMethod1(){
        println("NumberClass의 numberMethod1")
    }

    class OneClass(var a1:Int, var a2:Int) : NumberClass()
    class TwoClass(var a1:Int) : NumberClass(){
        override fun numberMethod1() {
            super.numberMethod1()
            println("TwoClass의 numberMethod1")
        }
    }
    class ThreeClass(var a1:Int, var a2:Double):NumberClass()
}

fun checkNumber(t1:NumberClass){

    when(t1){
        is NumberClass.OneClass -> {
            println("OneClass입니다")
            println(t1.a1)
            println(t1.a2)
            t1.numberMethod1()
        }
        is NumberClass.TwoClass -> {
            println("TwoClass입니다")
            println(t1.a1)
            t1.numberMethod1()
        }
        is NumberClass.ThreeClass -> {
            println("ThreeClass 입니다")
            println(t1.a1)
            println(t1.a2)
            t1.numberMethod1()
        }
    }
}

👩‍🏫 중간 정리

여기까지 느낀 바로는 Enum Class와 달리 sealed class는 상수가 아닌 하위 클래스들을 관리하기 위한 class 이고 이름에서 유추할 수 있듯이 sealed class를 상속받는 하위 클래스는 다른 클래스를 상속받을 수 없게 봉인! 하는 역할을 하는 것 같습니다. 이제 좀 더 알아보겠습니다.

📌 sealed class의 등장 배경

일반 추상(abstract) Class를 상속받는 하위 Class들은 Compiler가 상위 Class를 상속 받은 하위 Class의 종류를 알지 못합니다.

abstract class PersonState

class Running : PersonState()
class Walking : PersonState()
class Idle : PersonState()

fun getStateMessage(personState: PersonState): String{
    return when(personState){
        is Running -> "Peroson is running"
        is Walking -> "Peroson is Walking"
        is Idle -> "Peroson is Idle"
    }
}

위의 코드는 else branch를 추가하라는 오류를 만듭니다.

🤔 왜 else branch를 추가하라고 했을까요?

  • 컴파일러가 PersonSate를 상속받는 하위 클래스의 종류를 알지 못하기 때문입니다.
  • 그럼 이 케이스가 왜 문제가 될까요?

  • 위 코드에서 Idel에 대한 분기를 지우면 오류 없이 컴파일되는 것을 확인할 수 있습니다.
  • 이럴 경우 실제 사용되는 애플리케이션에 올라갔다면 Idle에 대한 처리가 되지 않아 애플리케이션은 제대로 동작하지 않습니다.
  • 즉, 코드에 문제가 있어도 컴파일 단에서 잡아내지 못하고 오류도 발생하지 않아 문제를 잡아내기가 매우 힘들어집니다.
🏳‍🌈 Sealed Class는 이런 문제를 쉽게 해결해 줍니다

📌Sealed Class 란

  • 추상 클래스(abstract class)로 상속받는 하위 클래스의 종류를 제한하는 특성을 가지고 있습니다.
  • 이를 통해 컴파일러가 sealed class의 자식 클래스가 어떤 것이 있는지 알 수 있습니다.

📜 예제 1

위의 예제를 그대로 추상 클래스에서 sealed class로 변경해 보겠습니다.

sealed class PersonState

class Running : PersonState()
class Walking : PersonState()
class Idle : PersonState()

fun getStateMessage(personState: PersonState): String{
    return when(personState){
        is Running -> "Peroson is running"
        is Walking -> "Peroson is Walking"
        is Idle -> "Peroson is Walking"
    }
}

 

sealed class PersonState의 자식 클래스에는 Running, Walking, Idle 세 가지만 가지고 있는 것을 알고 있기 때문에 일반 추상 클래스를 사용할 때와 달리 else branch에 대한 오류가 발생하지 않습니다.

📜 예제 2

위의 예제에서 또 다른 클래스를 하나 추가하고 분기 처리하지 않으면 어떻게 될까요?

  • sealed class인 Rest에 대한 처리가 안 돼있기 때문에 컴퍼 일러는 오류를 출력합니다.
  • Rest에 대한 분기를 처리하면 오류가 사라지는 것을 확인할 수 있습니다.

그런데 sealed class를 상속받은 class들에 왜 주의 표시가 되어 있을까요?🤔

'sealed' subclass has no state and no overridden 'equals()’
해석: sealed class의 subclass가 상태가 없고 equals( )를 오버라이드 하지 않습니다.

이는 상태(변수)가 있거나 equals를 override 할 때만 sealed class로 상속받으라는 말입니다.

Convert sealed subclass to object를 클릭하면 다음과 같이 코드가 변경됩니다.

Data object

2023년 release 된 kotlin 1.8.20 version에서 추가된 기능으로 일반 object와 동일하지만 내부적으로 toString(), euquals(), hasCode()를 구현하고 있습니다. 데이터 클래스와 유사하지만 object의 기능을 포함하는 것 같네요!

👩‍💻 sealed class의 다양한 서브 클래스 타입

sealed class의 서브 클래스들은 각자의 특성에 따라 다양한 생성자를 가질 수 있습니다. 

object는 데이터를 받아 상태가 변하지 않고 한 번만 객체가 생성되는 타입일 경우 사용합니다. 하지만 object 또한 IDE에서 data object Type으로 변경할 것을 권장하네요. 점점 코틀린의 버전이 업데이트되는 만큼 stable 되는 기능들이 많아져서 이 부분 또한 놓치지 않고 공부해야 할 것 같습니다.

sealed interface 

생성자를 필요로 하지 않는다면 Sealed Class의 생성자를 가지고 있지 않은 interface 도 사용할 수 있습니다.

🙇‍♂️ 후기

이렇게 한번 쭉 Sealed Class에 대해 알아봤는데 아직은 멀고 어렵게 느껴지는 것 같습니다. 실제로 프로젝트에서 사용해봐야 감이 좀 잡힐 것 같은데 어떻게 적용할지도 감이 잘 안 잡히네요😭 그래도 꾸준히 알아보면서 추후에 프로젝트 리팩토링 할 때 한번 사용해 보도록 노력해야겠습니다!

'KOTLIN' 카테고리의 다른 글

Channel 내부 동작 분석을 분석해보자  (0) 2025.02.07
Kotlin Value Class With Project Valhalla  (4) 2024.11.22
StateFlow가 중복된 값을 반환하지 않는 이유(DistinctUntilChanged)  (0) 2024.03.08
[Kotlin] LiveData 대신 StateFlow 사용하기  (1) 2024.01.15
[Kotlin] Coroutine Flow  (0) 2024.01.15
'KOTLIN' 카테고리의 다른 글
  • Channel 내부 동작 분석을 분석해보자
  • Kotlin Value Class With Project Valhalla
  • StateFlow가 중복된 값을 반환하지 않는 이유(DistinctUntilChanged)
  • [Kotlin] LiveData 대신 StateFlow 사용하기
빨주노초잠만보
빨주노초잠만보
  • 빨주노초잠만보
    과거의 나를 통해 미래의 나를 성장시키자
    빨주노초잠만보
  • 전체
    오늘
    어제
    • 분류 전체보기 (94)
      • TEKHIT ANDROID SCHOOL (4)
      • Android Architecture (7)
      • Android (40)
      • PROJECT (5)
      • KOTLIN (10)
        • 코루틴의 정석 (3)
      • BACK END (12)
      • CS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    의존성 주입
    saeled class enum class 차이
    repository
    Throttle
    Livedata
    sealed class vs enum class
    kotlin abstract class
    STATEFLOW
    interface vs abstract
    리사이클러뷰 풀
    kotlin 타입 소거
    kotlin array
    Repository Pattern
    Clean Architecture
    flow
    MVI
    코틀린 코루틴의 정석
    kotlin interface
    value class
    android clean architecture
    Room
    callbackflow
    DI
    orbit
    ThrottleFirst
    kotlin interface abstract 차이
    kotlin interface vs abstract
    android Room
    sealed class
    DataSource
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
빨주노초잠만보
[Kotlin]Sealed Class란 무엇일까 ?
상단으로

티스토리툴바