interface Top {
data class Sub1(val ss: String): Top
data class Sub2(val ss: String): Top
data class Sub3(val ss: String): Top
data object Sub4: Top
class Sub5: Top
}
fun test(top: Top) {
when (top) {
is Top.Sub1 -> {}
is Top.Sub2 -> {}
is Top.Sub3 -> {}
}
}
클래스를 계층화할 때, abstract class
나 interface
가 있음에도 왜 sealed class
나 sealed interface
를 사용하는걸까?
단순, ViewModel에서 관습적으로 sealed interface
를 사용해 상태관리를 하기에 무조건적으로 따라하다 갑자기 든 의문이었다. 충분히 일반적인 interface
나 abstrace class
로도 처리할 수 있는데 말이다.
이유는 하위 타입 클래스들이 추가 정의될 때, 컴파일러를 통해 오류를 잡기 위함이다. 위 코드의 Top
인터페이스는 자식으로 5개의 클래스를 가지고 있다. 하지만 when
문으로 분기처리할 때, 3개의 하위타입 지정했음에도 불구, 컴파일러가 에러를 지적해주지 않는다.
위와 같은 코드는 치명적인 약점이 있다.
top
아규먼트로 Sub4
또는 Sub5
타입이 들어온다면, 앱이 크래시난다.Top
인터페이스의 하위 타입이 추가될 때, 이에 맞는 하위 타입 처리를 어디에 해야할지 개발자가 놓칠 수 있다.else
문으로 분기처리하여 진행 시, 앱 크래시는 막을 수 있다 쳐도, 정확한 하위 타입을 알 수 없다.반면, Top
인터페이스 선언에 sealed
선언을 추가하면 위 문제가 모두 해결된다. 아래 when
문을 보면 알겠지만, compiler가 빨간색 줄을 친절히 그어주고 있다. 이는 Top
인터페이스 하위 자식이 when
문에 모두 정의되어있지 않기에, 하위 타입을 모두 정의해달란 뜻이다.
위 처럼 compiler가 빨간 줄을 그어줄 땐, 앱 자체가 빌드 되지 않는다. 따라서 개발자가 자신의 실수를 쉽게 눈치채고 코드를 수정할 수 있게된다. 이에, Top.Sub4
와 Top.Sub5
를 추가하면 when
문의 빨간 줄이 사라지는걸 볼 수 있다.
이러한 내용은 Kotlin공식 홈페이지에도 나와있다.
abstract class
나 interface
를 사용할 땐, when
문을 사용한 하위 타입 분기처리를 놓침으로써 앱의 크래시 가능성을 배제할 수 없다. (이에 else
문을 사용하는 것도 올바른 해결책이 아니다.)
하지만 sealed interface
or sealed class
는 compiler가 하위 타입 분기 로직 작성의 강제 및 에러를 표시해주므로 앱을 더 안전하게 해준다.