caffeine-library / Domain-Driven-Design

🌱 에릭 에반스의 '도메인 주도 설계'를 읽는 스터디
4 stars 0 forks source link

[additional] sealed class - 봉인된 클래스 #49

Closed leejaeseung closed 1 year ago

leejaeseung commented 1 year ago

연관 챕터

조사 내용

저번 이슈에서 나왔던 불변성, 그리고 이번 장에서 단언(Assertion)을 사용해 객체의 형태를 고정하는 방법이 나왔는데 코틀린, 스칼라에선 sealed class 로 깔끔하게 이를 표현할 수 있습니다. (자바 15 부터 지원한다고 하는데 다른 분들도 많이 사용하시는지 궁금하네요!)

책에선 Paint 가 Mixed Paint, Stock Paint 두 형태로만 표현될 수 있도록 설계하였는데, sealed class 로 작성한다면 다음처럼 할 수 있습니다. (책에선 테스트코드 혹은 Assertion 으로 객체의 상태를 제한하는 방법을 소개하고 있는 것 같네요.)

sealed trait Paint

object Paint {
    case class MixedPaint() extends Paint
    case class StockPaint() extends Paint
}

위 코드가 일반적인 상속과 다른 점은 Paint 의 상태에 따라 분기해야할 때, MixedPaint/StockPaint 가 아닌 경우는 아예 배제할 수 있다는 점입니다. 만약 일반적인 상속이었다면 Paint 의 상태에 대한 예외 처리를 반복적으로 해줘야겠죠 (저번 주 불변식 관련해서 비슷한 얘기를 했던 것 같네요)

예전까진 sealed class 의 개념만 알고 이걸 어디다 쓰지..?(sealed class 는 외부에서 상속이 되지 않으니..) 라는 생각으로 별 관심을 두지 않았는데, 회사의 복잡한 코드를 최대한 간결하게 짜려다보면 필수불가결하게 사용하게 되는 것 같네요.

scala 에선 sealed class 와 패턴 매칭을 사용하면 아래처럼 깔끔한 분기가 가능합니다. ㅎㅎ

// sealed class 를 사용하지 않은 경우
paint match {
    case MixedPaint() => println("난 MixedPaint!")
    case StockPaint() => println("난 StockPaint!")
    case _ => throw Exception("난 뭐지..?")  // 불필요한 예외 처리 코드
}

// sealed class 를 사용한 경우
paint match {
    case MixedPaint() => println("난 MixedPaint!")
    case StockPaint() => println("난 StockPaint!")
}