[Kotlin] sealed class
가위바위보에서 낼 수 있는 선택지는 가위, 바위, 보 3개뿐이다. 따라서 가위바위보의 참가자들은 다른 선택지를 내지 말아야 한다. 현실에서는 상대방의 강력한 항의와 눈초리를 통해 제한되지만, 프로그래밍에서도 그렇게 강제할 수 있을까?
interface RSPOption
class Rock: RSPOption
class Scissors: RSPOption
class Paper: RSPOption
// 이건 반칙이다
class Gun: RSPOption
짖궂은 개발자가 가위바위보에 ``Gun``을 추가하지 못하도록 막을 수 있는 방법이 없을까?
있으니까 글을 썼겠지?
sealed class
Kotlin의 sealed class를 사용하면 외부 개발자가 상속할 수 없는 상위 타입을 만들 수 있다.
sealed class RSPOption {
class Rock: RSPOption()
class Scissors: RSPOption()
class Paper: RSPOption()
}
// 다른 파일에서는 RSPOption을 상속받을
sealed class는 클래스가 정의된 파일에서만 상속받을 수 있다. 위에서는 ``RSPOption`` 안에 모든 하위 클래스를 정의했지만, 같은 파일 안에서는 어디서든 상속할 수 있다.
final class는 절대로 상속될 수 없는 반면 sealed class는 파일 내에서만 상속될 수 있다는 차이점이 있다.
when에 안성맞춤
sealed class는 외부에서 상속받을 수 없는 특성상 자식 클래스가 컴파일 시간에 정해진다. 그래서 다음과 같은 코드를 짤 수 있다.
fun print(option: RSPOption) = when(option) {
RSPOption.Rock -> println("Rock!")
RSPOption.Scissors -> println("Scissors!")
RSPOption.Paper -> println("Paper!")
}
``else`` 구문이 없다는 점에 주목해야 한다. 일반적인 ``open class``나 ``interface``는 누구나 자유롭게 상속받을 수 있어서, 내가 알고 있는 자식 클래스 외에 다른 자식 클래스가 얼마든지 추가될 수 있다. Kotlin은 이런 경우를 대비하여 ``when`` 문에 ``else``를 반드시 추가하도록 강제하고 있다.
그러나 sealed class를 사용하고 ``when``에서 모든 자식 클래스를 처리하는 분기를 작성했다면 ``else``문을 작성하지 않아도 된다.
또, sealed class의 새로운 자식 클래스가 추가되었다면 ``when`` 구문에 새로운 분기를 추가가해야만 한다. 컴파일 에러 때문에 하기 싫어도 해야 한다. 수정이 필요한 부분을 콕 집어 주는 고마운 기능이다.