Kotlin Class(Inner, Enum, Sealed)

cmplxn·2020년 12월 26일
0

Inner Class

여러가지 목적이 있을 수 있지만, 클래스 내부에 클래스를 선언하는 경우가 있다.
이때 바깥쪽 클래스에 대한 참조가 가능한가의 여부로 경우를 나눌 수 있다.

내부 클래스

첫번째로는 바깥쪽 클래스에 대한 참조를 저장하는 경우다.
Java에서는 별다른 키워드 없이 내부에 클래스를 선언하면 바깥 클래스에 접근할 수 있다.
하지만 Kotlin에서는 inner라는 키워드를 붙어야 바깥 클래스에 접근할 수 있다.

class A {
    inner class B {
        val outer = this@A
    }
}

중첩 클래스

두번째로는 바깥쪽 클래스에 대한 참조를 저장하지 않는 경우다.
Java에서는 static 키워드를 붙여 내부에 클래스를 생성했다.
Kotlin에서는 오히려 이 경우를 일반적인 경우로 취급하여 키워드를 붙이지 않으면 된다.
바깥 클래스에 대한 참조가 필요하지 않는 경우는 이 방법으로 구현하자.

class A {
    class B {
        val outer = this@A // compile error
    }
}

Enum Class

Enum 기본

Enum Class는 다른 언어의 Enum과 비슷한 기능을 가진다.
기본적으로 0을 시작으로 열거상수를 ,로 구분하여 나열하여 정의할 수 있다.

또한 이 열거상수들은 그 자체로서 객체다.
그러므로 이들은 프로퍼티와 함수를 가질 수 있다.

프로퍼티를 위해서는 enum class의 생성자를 추가하던가 추상 프로퍼티를 선언하면 된다.
함수를 위해서는 추상 함수를 선언하면 된다.
대신 모든 열거상수는 똑같이 프로퍼티와 함수를 가져야한다.
선택적으로 어떤 프로퍼티만 가진다던가, 어떤 함수만 override할 수는 없다.

참고로 프로퍼티와 함수를 가지기 위해 추상 함수, 프로퍼티를 선언한다면 열거상수 부분 끝에 ;를 추가해야한다.
Kotlin에서 세미콜론은 쓸일이 없는데 여기서 등장한다!

글보다는 코드를 보는게 편하므로 아래 예시 코드를 보면서 이해해보자.

enum class Direction(val lowerCase: String) { // 생성자 프로퍼티
    NORTH("north") { // 0
        override fun clockWise() = "EAST"
    }, // ,으로 구분한다.
    SOUTH("south") { // 1
        override fun clockWise() = "WEST"
    }; // 열거상수들 끝에 ;으로 추상함수 부분과 구분한다.

    abstract fun clockWise(): String // 추상 함수
}

when과 함께 사용

enum을 사용하면 when을 사용할 때, else 없이 모든 조건을 나열할 수 있다.

fun exhaustiveWhen(dir: Direction): String =
        when (dir) {
            Direction.NORTH -> Direction.NORTH.clockWise()
            Direction.SOUTH -> Direction.SOUTH.clockWise()
        }

이런 구문이 여러개 있을 때 Direction에 WEST가 추가되면 실수로 누락할 수 있다.
하지만, enum을 사용하면 윗 코드 부분에서 컴파일에러가 발생하여 방지할 수 있다.
그렇지 않고 else를 이용했다면 예상치 못한 런타임에러에 직면할 수 있다.

유용한 내장 함수

그리고 Enum Class를 다룰 때 쓸 수 있는 내장 함수들도 있다.
ordinal, name과 같은 기본적인 것 뿐만아니라
enum 값 배열을 반환하는enumValues(), 값을 찾아주는enumValueOf(name: String)도 있다.

Sealed Class

Enum Class와 비슷한 역할을 하는 클래스로 Sealed Class가 있다.
정확히 말하자면 Sealed Class는 클래스 계층 확장을 제한해주는 상위 클래스다.
목적은 계층 확장의 제한이므로 생성자 자체도 private으로, 그 자체로는 생성할 수 없는 클래스다.

Enum Class와 가장 큰 다른 점은 객체별로 프로퍼티와 함수를 다르게 구성할 수 있는 점이다.

아래 예시를 보면 조금 더 이해하기 쉬울 것이다.

sealed class Test {
    // 객체별로 다른 프로퍼티
    class A(val int: Int) : Test()
    class B(val double: Double) : Test()
}

fun test(test: Test) {
    when (test) { // else 필요없이 exhaustive
        is Test.A -> println("A")
        is Test.B -> println("B")
    }
}

또한 Sealed Class에는 Enum Class에 있던 enumValues(), enumValueOf() 같은것도 없다.

그러므로 Enum Class는 Sealed Class의 부분집합 또는 특수 케이스로로 볼 수 있다.

참고

Enum vs Sealed
Sealed Class를 사용한 UI 상태 관리

profile
Android Developer

0개의 댓글