Developing Myself Everyday
Published 2023. 5. 26. 11:19
Sealed Class Android/Kotlin

 때로는 우리가 프로그램에서 표현하고 싶은 개념이 몇 가지 정해진 변종의 집합으로 구성될 때가 있다. 이런 경우에는 똑같은 타입을 공유하는 미리 정의된 상수 집합을 표현하는 이넘 클래스를 사용해 표현할 수 있다.

 

이넘 클래스에 대한 설명은 아래의 게시글에서 참고할 수 있다.

 

Enum Class

이넘 클래스란? 이넘 클래스는 미리 정의된 상수들로 이뤄진 제한된 집합을 표현하는 클래스다. 정수, 문자열 등과 비교할 때 이넘을 사용하면 어떤 값이 가능한 범위 안에 들어가 있는지를 일

everyday-develop-myself.tistory.com

 

 하지만 어떤 경우에는 각 종류별로 애트리뷰트가 다를 수 있다. 한번 어떤 계산이 성공인지 실패인지를 표현하는 예제를 추상 클래스를 사용해 만들어 보겠다. 다만 성공인 경우에는 생성된 결과가 들어있고, 실패인 경우에는 실패 이유에 대한 정보가 들어있다. 

 

import java.lang.Exception

abstract class Result {
    class Success(val value: Any): Result() {
        fun showResult() {
            println(value)
        }
    }

    class Error(val message: String): Result() {
        fun throwException() {
            throw Exception(message)
        }
    }
}

fun runComputation(a: Int, b: Int): Result {
    return Result.Success(a + b)
}

fun main() {
    val message = when(val result = runComputation(1, 2)) {
        is Result.Success -> "Completed successfully: ${result.value}"
        is Result.Error -> "Error: ${result.message}"
        else -> return
    }
    println(message)
}

 

 이 구현에는 흠이 있다. 이 구현은 Result의 변종을 Success나 Error로 제한하지 못한다. 다른 클라이언트가 다음과 같이 새로운 하위 클래스를 추가해도 막을 방법이 없다.

 

class A: Result()

 

 그리고 이런 서브 클래싱이 가능하다는 점이 when 식에서 else가 필요한 이유이기도 하다. 컴파일러는 result 변수가 Success나 Error 인스턴스만 담는다는 사실을 알 수 없기 때문에 else 절을 추가하라고 강제한다.

 

 코틀린에서는 Sealed Class나 인터페이스를 통해 이런 문제를 극복할 수 있다. 그 방법은 다음과 같다.

 

 

봉인된 클래스를 사용해 문제 극복하기


 어떤 클래스를 sealed로 지정하면, 이 클래스를 상속하는 클래스는 내포된 클래스 또는 객체로 정의되거나 같은 파일 안에서 최상위 클래스로 정의돼야만 한다.  

 이넘과 마찬가지로 봉인된 클래스도 불필요한 else를 쓰지 않아도 되는, 빠진 부분이 없는 when 형태를 지원한다. 이제 봉인된 클래스를 사용한 코드를 보겠다.

 

sealed class Result {
    class Success(val value: Any): Result() {
        fun showResult() {
            println(value)
        }
    }

    class Error(val message: String): Result() {
        fun throwException() {
            throw Exception(message)
        }
    }
}

fun runComputation(a: Int, b: Int): Result {
    return Result.Success(a + b)
}

fun main() {
    val message = when(val result = runComputation(1, 2)) {
        is Result.Success -> "Completed successfully: ${result.value}"
        is Result.Error -> "Error: ${result.message}"
    }
    println(message)
}

 

 

 

 

 

 

 

 

 

 

 

 

profile

Developing Myself Everyday

@배준형

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!