Kotlin - Enum 정의와 사용 방법 알아보기

Enum은 Enumeration를 줄여서 사용하는 단어로 한국 말로는 열거형이라고 표현하는 단어입니다. 여기서 이야기하는 열거라는 단어는 `나열`되는 것들을 의미하는데, 프로그램에서는 특정한 특질이나 속성으로 분류해서 사용하는 값들을 나열할 때 쓰입니다. 간단히 말해 상수들을 나열해 놓은 것을 열거형(Enum)이라고 표현합니다.

열거(Enumeration) 개념 알아보기

 일반적으로 프로그램을 개발할 때 상수(Constant)로 지정해서 사용하면 좋은 값들이 있습니다. 예를 들어 최대 값과 같이 값(리터럴) 자체가 의미를 가지고 있는 경우입니다.

fun main() {
    val number = 10
    validateNumber(number)

    if (number > 9) {
        // 사용하지 못하는 값을 전달 받은 경우 프로세스 종료
        return
    }
}

// 값의 유효성을 확인하고 메시지를 출력한다.
fun validateNumber(value: Int) {
    if (value > 9) {
        println("사용할 수 있는 값의 최대는 9 입니다.")
        return
    }
}

 최대 값을 검증하는 비즈니스를 가진 예제 코드가 있다고 가정한다면 예제처럼 최댓값을 직접 입력해서 사용하게 되면 어떻게 될까? 당장은 큰 문제가 없다고 생각되지만 최댓값을 사용하는 곳이 10, 11, 12.. 이런 식으로 점진적으로 늘어나는 상황에 맞닥뜨리게 되면 최댓값을 관리하기가 어려워진다.

object Constants {
    const val MAX = 9
}

fun main() {
    val number = 10
    validateNumber(number)

    if (number > Constants.MAX) {
        // 사용하지 못하는 값을 전달 받은 경우 프로세스 종료
        return
    }
}

// 값의 유효성을 확인하고 메시지를 출력한다.
fun validateNumber(value: Int) {
    if (value > Constants.MAX) {
        println("사용할 수 있는 값의 최대는 9 입니다.")
        return
    }
}

 이럴 때 상수(Constant)를 정의해서 사용하면 변수 이름으로 값의 의미도 정의할 수 있고, 여러 곳에 사용되어도 손쉽게 관리할 수 있게 됩니다. 최솟값이 필요해져서 추가로 상수를 정의해야 한다면요?

const val MAX: Int = 9
const val MIM: Double = 0.0

 네 위의 예제처럼 하나의 변수를 추가해서 정의하면 됩니다. 그런데 코드를 자세히 들여다보면 한 가지 아쉬운 점이 있습니다. Constants를 기준으로 분류해서 정의는 되었지만 값을 정의하는 형태가 일정하지 않습니다. 최댓값은 Int 타입으로 정의된 반면 최솟값은 Double 타입으로 정의되었습니다. 만약 내가 아닌 다른 누군가가 생각지 못한 값들을 무작위로 추가하게 된다면요?

enum class Numbers(val number: Int) {
    MAX(9),
    MIN(0)
}

 

 열거형 클래스(Enum)는 이런 상수의 문제를 보완해서 상수 값들을 그룹화시켜 나열해 사용하는 값들을 의미합니다. 조금 더 확실히 이야기하면 상수 값이 아니라 상수 객체(클래스)를 이야기합니다.

Enum 정의와 사용 방법 - valueOf()

 이번에는 코틀린에서 열거형 클래스를 사용하는 방법에 대해 알아보겠습니다. 열거형 클래스를 정의하는 방법은 단순합니다. enum 키워드를 class와 같이 사용하면 됩니다. Enum의 정의에서 살펴본 최댓값과 최솟값으로 Enum을 사용하는 방법에 대해 알아보겠습니다.

enum class Numbers {
    MAX,
    MIN;
}

 Enum은 기본으로 문자 값을 표현하기 때문에 최댓값과 최솟값을 정의한다면 위와 같이 정의할 수 있습니다. 또한 Enum은 valueOf() 함수를 통해 값을 찾을 수 있습니다. valueOf() 함수는 Enum이 제공하는 강력한 기능 중 하나이기 때문에 잘 사용하면 유용한 함수입니다.

Enum의 valueOf() - Kotlin

 자 이제는 Enum이 문자 값으로 사용하는 게 아니라 값을 가지게 해서 상수 객체로 사용해보겠습니다.

enum class Numbers(val value: Int) {
    MAX(9),
    MIN(0);
}

fun main() {
    println(Numbers.MAX.value)
    // 9
    
    val maxNumber = Numbers.valueOf("MAX")
    println(maxNumber.value)
    // 9
}

 Enum은 클래스이기 때문에 예제처럼 프로퍼티를 정의해 값을 가질 수 있게 할 수 있습니다. 정의한 Enum 값은 직접 값(value)에 접근할 수도 있고, valueOf() 함수를 사용해 값을 찾아 쓸 수도 있습니다. 그뿐일까요? Enum은 함수도 가질 수도 있습니다.

Enum 활용 방법with 인터페이스

 이번에 Enum에 대해 알아볼 내용은 바로 인터페이스를 사용해 Enum을 정의하고 함수를 가지게 하는 방법입니다. 객체지향 프로그래밍에서 인터페이스는 꽃과 같은 존재입니다. 그리고 Enum은 클래스이기 때문에 인터페이스를 사용할 수 있습니다. Enum과 Interface가 만난다면 어떻게 될까요?

interface OperatorExecutor {
    fun apply(num1: Int, num2: Int): Int
}

enum class Operator(val symbol: String) : OperatorExecutor {
    PLUS("+") {
        override fun apply(num1: Int, num2: Int): Int {
            return num1.plus(num2)
        }
    },
    MINUS("-") {
        override fun apply(num1: Int, num2: Int): Int {
            return num1.minus(num2)
        }
    };

    companion object {
        fun symbolOf(symbol: String): Operator {
            return values()
                    .firstOrNull{it.symbol == symbol}
                    ?: throw NoSuchElementException("정의되지 않은 기호")
        }
    }
}

fun main() {
    println(Operator.symbolOf("+").apply(1, 1))
    // 2

    println(Operator.symbolOf("-").apply(1, 1))
    // 0
}

 

 OperatorExecutor 인터페이스를 상속한 Operator는 연산 기호(+, -)에 따라 연산식을 구현하도록 정의해보았습니다. 그리고 valueOf()는 문자 값으로 Operator를 찾기 때문에 기호로 Operator를 찾을 수 있는 symbolOf() 함수도 추가해 Operator의 활용성을 높여보았습니다.

 

 예제 코드와 같이 Enum은 인터페이스를 상속받을 수 있기 때문에 값 외에도 함수도 포함할 수 있는 장점이 있습니다. 인터페이스를 사용해 Enum을 정의한다면 조금 더 재미있게 코틀린으로 프로그래밍을 할 수 있습니다.

반응형

'프로그래밍 > 코틀린' 카테고리의 다른 글

Kotlin - 함수와 변수 기초 배우기  (2) 2022.05.17

댓글

Designed by JB FACTORY