sealed

  • sealed Class는 sealed Class로 정의된 클래스의 종류에 따라 다른 작없을 처리해야 할 때 매우 유용하다.

  • enum클래스를 확장한 개념.

  • 각 종류별로 하나의 인스턴스만 생성되어 있는 enum클래스와 달리 인스턴스를 여러개 생성 할 수 있다.

  • Java에서는 클래스에 final키워드를 붙이거나 생성자를 private로 생성하지 않는이상, 모든 클래스가 상속이 가능하기 때문에 악용의 우려가 있으므로 상속을 제한하는 클래스가 필요하다.

  • sealed 키워드를 클래스 앞에 붙이면 같은 프로젝트 안에서는 상속이 가능하고 외부 모듈에서는 상속이 불가해진다.

//sealed class를 상속받는 모든 하위 클래스들은 그 수퍼클래스에 중첩되어야 한다.
sealed class Expr {
    data class Const(val number: Double): Expr()
    data class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}

//하지만 같은 파일내에 정의하는 경우, 클래스 외부에 선언해도 무방하다.
sealed class Expr {
    object NotANumber : Expr()
}

data class Const(val number: Double): Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()


fun eval(e: Expr): Double = when(e) {
    is Const -> e.number
    is Sum -> eval(e.e1) + eval(e.e2)
    NotANumber -> Double.NaN  -> // object타입은 별도 캐스팅을 할 필요가 없기때문에 is를 붙이지 않는다.
    //가능한 모든 케이스들에 대해 분기를 작성해 주었기 때문에 else 문(기본분기)을 작성할 필요가 없다.
}

// enum class와 매우 유사하다. enum의 확장판.
// enum은 각 object들이 같은 생성자와 같은 함수들을 갖지만, sealed class는 object의 hierarchies 제한만 갖고
// 별도의 생성자와 프로퍼티를 가질 수 있다.

//sealed class를 상속받은 클래스는 꼭 같은 파일에 있을 필요는 없다.

만약 Expr 이 한정클래스가 아니라면 Expr 을 상속하는 클래스가 얼마든지 있을 수 있기에, when 문에 else 절이 반드시 필요하게 된다.

그리고 한정클래스에서는 새롭게 상속을 받는 클래스가 추가되게 되었을때 그 새로 추가된 유형의 처리가 없다면 컴파일에러를 뱉어주어서 새 유형에 대한 처리가 누락되는 것을 방지할 수 있지만, 비 한정클래스의 경우 컴파일단에서 에러가 잡히지 않기 때문에 런타임 에러가 발생할 수 있다.

enum class 와 매우 유사하다. enum 의 확장판. enum 은 각 object 들이 같은 생성자와 같은 함수들을 갖지만, sealed class는 object 의 hierarchies 제한만 갖고 별도의 생성자와 프로퍼티를 가질 수 있다.

sealed class를 상속받은 클래스는 꼭 같은 파일에 있을 필요는 없다.

인터페이스로도 같은효과를 낼 수 있다.

//Interface
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int = when(e) {
    is Num -> e.value
    is Sum -> eval(e.right) + eval(e.left)
    else -> throw IllegalArgumentException("Unknown expression")
    //else분기를 처리해주어야만 한다.
}

비슷한 용법이지만 when표현식에서 else를 처리해 주어야만하는가 아닌가의 차이가 있다.

새로운 서브클래스를 추가해주어도 컴파일러가 그걸 알지못한다. 추가된 클래스에 따른 분기를 작성해주지 않으면 버그가 발생할 위험이 있다.

Sealed 나 enum 을 사용하게 되면 case 들이 명확해진다. 따라서 상정하지 않은 케이스를 사전에 방지하는 효과가 있고, 사전에 정의한 case 에 대해 실수로 인한 누락을 컴파일단에서 잡아준다. 즉 훨씬 안전하고 명확한 코딩을 할 수 있다.

Last updated