[Kotlin] Sealed Class and Interface

문승연·2023년 11월 30일
0

Kotlin 기본

목록 보기
10/11

Sealed Class? 왜 필요한가

하나의 부모 Class Parent가 존재하고 해당 Class를 상속받는 여러개의 자식 Class Child가 여러개 존재한다고 가정해보자.

이때 컴파일러는 Parent를 상속받는 자식 Class Child가 얼마나 존재하는지 애초에 존재는 하는지 알지 못한다.

예를 들어, 사용자의 상태를 클래스로 나타내기 위해 추상 클래스 PersonState를 만들고 이를 상속받는 3개의 자식 클래스 Running, Walking, Idle을 만들고자 할 때, 아래와 같이 코드로 구현할 수 있다.

abstract class PersonState

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

이때 각 PersonState 별로 상태 메세지를 얻고자 한다면

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

위와 같이 getStateMessage 함수를 만들 수 있다.

하지만 이 코드는 else branch를 추가하라는 오류 메세지를 발생시킨다.

개발자는 PersonState의 자식 클래스가 Running, Walking, Idle 3가지 밖에 없다는 걸 알지만 컴파일러 입장에서는 PersonState의 자식 클래스가 얼마나 있는지 모르니 else로 예외 처리를 필요하다고 하는 거다.

하지만 반대로 else branch를 추가하는 대신 다른 PersonState 상태에 대해 처리해주지 않는다면?

fun getStateMessage(personState: PersonState): String {
	return when (personState) {
		is Running -> "Person is running"
        is Walking -> "Person is walking"
        else -> "No State"
	}
}

이 코드는 정상적으로 컴파일된다. 하지만 Idle 상태를 가지고 있을때도 "No State"를 출력하는 정상적이지 않은 동작을 할 것이다.

위와 같은 문제를 Sealed Class를 이용해서 효과적으로 해결할 수 있다.

Sealed Class란

Sealed Class는 추상 클래스(abstract class)의 하나로써 상속 받는 자식 클래스의 종류를 제한하는 특성을 갖고 있다.

위의 예시 코드를 Sealed Class를 사용해서 구현하면 아래와 같다.

sealed class PersonState

class Running : PersonState()
class Walking : PersonState()
class Idle : PersonState()
fun getStateMessage(personState: PersonState): String {
	return when (personState) {
		is Running -> "Person is running"
        is Walking -> "Person is walking"
        is Idle -> "Person is doing nothing"
	}
}

Sealed Class로 PersonState 클래스를 구현하면 getStateMessage 함수가 오류를 발생시키지 않는다.

Sealed Class가 자식 클래스를 Running, Walking, Idle 3가지로만 제한했다는 것을 컴파일러가 알고 있기 때문이다.

Object로 상속 받기

sealed class PersonState

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

이 Sealed Class는 정상적으로 작동하나 한 가지 문제가 있다. class에 주의(밑줄 표시)가 뜨는 것을 확인할 수 있는데 경고문은 다음과 같다.

sealed subclass has no state and no overridden equals()

즉, 상태(변수)가 있거나 equals()를 override할 때만 class로 상속 받아야한다는 뜻이다.

위의 예시와 같은 경우에는 class가 아닌 object 로 상속받을 수 있다.

sealed class PersonState

object Running : PersonState()
object Walking : PersonState()
object Idle : PersonState()

Sealed Interface

sealed 는 Class 뿐만 아니라 Interface에서도 비슷하게 활용 가능하다.

sealed interface Error

sealed class IOError(): Error

class FileReadError(val file: File): IOError()
class DatabaseError(val source: DataSource): IOError()

object RuntimeError : Error

레퍼런스)

  1. [Kotlin] Kotlin sealed class란 무엇인가?
  2. Sealed classes and interfaces
profile
"비몽(Bemong)"이라는 앱을 개발 및 운영 중인 안드로이드 개발자입니다.

0개의 댓글