[Kotlin] sealed class (feat. Android)

jmi·2024년 11월 11일
post-thumbnail

Sealed Class란?

  • 클래스 계층 구조에서 상속받을 수 있는 클래스의 종류를 제한할 때 사용한다.
  • 미리 정의된 여러 상태를 표현할 수 있지만, 각 상태마다 다른 데이터와 동작을 가질 수 있는 클래스
  • 컴파일러에서 sealed class의 자식 클래스가 어떤 것이 있는지 알 수 있다.
    • 그래서 주로 when 구문과 함께 사용하면, 모든 경우의 수를 처리하도록 강제할 수 있어 안전한 코드 작성에 도움
  • 자기 자신이 추상 클래스이다.
    • 자신을 상속 받는 어려 서브 클래스들을 가질 수 있다.
  • 하나의 파일에 지정된 서브 클래스들을 하나로 묶어주는 역할
  • 제한된 서브 클래스만을 사용하기 때문에 좀더 엄격한 클래스 관리 가능

Sealed Class의 특징

  • sealed 클래스의 서브 클래스들은 반드시 같은 파일 내에 선언되어야 한다.
    • 단, sealed 클래스의 서브 클래스를 상속한 클래스들은 같은 파일 내에 없어도 된다.
    • 코드 가독성을 높이고, sealed class가 표현하는 상태들이 한 곳에 모여있어 관리가 쉬워진다.
  • when 구문을 사용할 때, 모든 하위 클래스를 처리하지 않으면 컴파일러가 경고를 주기 때문에 모든 경우의 수를 빠짐 없이 처리 가능
  • sealed 클래스는 기본적으로 abstract 클래스이다.
    • sealed class 자체는 객체를 직접 생성할 수 없으며 추상 클래스처럼 역할한다.
    • 따라서, sealed class를 상속 받는 하위 클래스에서만 인스턴스 생성이 가능하다.
  • sealed 클래스는 private 생성자만 갖게 된다.

Sealed Class의 장점

  • 코드 안정성 향상
    • 컴파일 타임에 모든 하위 클래스를 확인하고 사용할 수 있기 때문에 런타임에서 예상치 못한 동작을 방지하여, 코드 안정성을 향상시킨다.
  • 가독성 향상
    • 클래스의 계층 구조가 명확해지므로 코드의 가독성과 유지보수성이 향상
  • 패턴 매칭
    • 일반적으로 타입이 서로 다른 값들을 패턴으로 지정하고, 해당 값이 각각 어떤 타입인지 판별하는 기능
    • 이를 통해 코드를 더 간결하고 가독성 높게 작성 가능

Sealed Class가 유용한 경우

  • UI 상태 관리
    • 화면 로딩, 성공, 실패 등 UI 상태를 관리할 때 각 상태를 안전하게 처리 가능
  • API 응답 처리
    • 네트워크 호출의 결과를 성공, 실패, 로딩 등으로 구분하고 싶을 때
  • 복잡한 상태 표현
    • 여러 상태를 갖는 객체의 상태 전환을 간편하고 안전하게 처리하고 싶을 때

사용 예시

sealed class UiState {
    object Loading : UiState()
    data class Success(val data: List<String>) : UiState()
    data class Error(val message: String) : UiState()
}

위에서 정의한 sealed class를 이용해 아래처럼 ViewModel에서 상태를 관리할 수 있다.

class MyViewModel : ViewModel() {
    private val _uiState = MutableLiveData<UiState>()
    val uiState: LiveData<UiState> get() = _uiState

    fun fetchData() {
        _uiState.value = UiState.Loading
        viewModelScope.launch {
            try {
                val data = repository.getData() // 데이터 가져오는 코드
                _uiState.value = UiState.Success(data)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "Unknown Error")
            }
        }
    }
}

그러면 View에서 이렇게 상태에 따라 UI를 업데이트 할 수 있다.

viewModel.uiState.observe(viewLifecycleOwner) { state ->
    when (state) {
        is UiState.Loading -> showLoadingIndicator()
        is UiState.Success -> showData(state.data)
        is UiState.Error -> showError(state.message)
    }
}
profile
안드로이드 개발자가 되자

0개의 댓글