Kotlin의 sealed class를 능숙하게 사용하다

18478 단어 Kotlin
Kotlin은 쓰기가 너무 쉬워요. 일하는 안드로이드 개발뿐만 아니라 관심 있는 데스크톱 프로그램도 Kotlin으로 씁니다.
Kotlin은 편리한 언어 기능을 많이 가지고 있습니다.
그중에서 저는 개인적으로 sealed class를 좋아하기 때문에 이 매력을 소개하고 싶습니다.

sealed class


기준 일본을 대표하는 Kotlin 에벤저의 블로그입니다.
한마디로 계승을 제한하는 데 쓰이는 수식부호다.sealed를 가진 클래스를 계승하려면 어떤 조건을 만족시켜야 한다.
kotlin 1.2.1 현재,sealedclass에 삽입된 클래스와 같은 파일에서 설명한 클래스만 계승할 수 있습니다.
// in Base.kt
sealed class Base {
    object SubOne: Base()    // ok
    object SubTwo: Base()    // ok
}

class SubThree: Base()       // ok




// in Other.kt
object SubFour: Base()       // ng
그렇군요. 알겠습니다.
그런데 이걸 어떻게 사용해야 좋을까요?

sealedclass의 용도


Kotlin 참조에 따르면 이런 느낌의 용도인 것 같다.
유한 범위 유형 중 하나의 값을 원한다면, 클래스 차원 구조의 범위를 한정하기를 원할 때Sealedclass를 사용합니다.
이것은 enumclass의 확장판과 같다. enum의 상량은 하나의 실례로 존재하지만, sealedclass의 하위 클래스는 여러 개의 실례로 상태가 있을 수 있다.
Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type. They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.
그렇구나, 몰랐어.
그냥 제가 번역을 잘 못했나봐요.
하지만 편리한 사용법이 있습니다.
백문이 불여일견.우리 구체적으로 한번 봅시다.
우리 순서대로 봅시다.

규정된 값을 선택하고 싶지만 사용자 정의 값을 지정하고 싶습니다


참고자료에'확장판 enum 같은 것'이라고 쓰여 있으니 그 인상으로 사용해 보세요.

색상


예를 들어 어떤 색으로 가득 칠하고 싶은지.
fun fill(color: Color) {
    ...
}
Color 사용하기 편리하도록 기본 정의된 몇 가지 색을 준비했습니다. 어떤 경우에는 임의의 값을 받아들일 수 있습니다.
그럼 어떻게 발표해야 좋을까요?
정의된 것 중에서 무엇을 선택할 때 가장 먼저 떠오르는 것은 엔움!우리 먼저 엔움에 성명합시다.

enum class Color {
    RED,
    GREEN,
    BLUE
}
사용자 정의 값은 어떻게 합니까?성명 후,enum 상량은 값을 가질 수 없습니다.
CMYK가 나와도 색상을 지정하려는 주문이 있다면?약간 머리를 안고 있는 것 같은데...
거기서 사용할 수 있는 것은 sealed class입니다.
sealed class Color {
    // objectは単一インスタンスのみもつクラスを作るキーワード。
    // つまりenum定数を作るのとあまり変わらない。
    object Red: Color()
    object Green: Color()
    object Blue: Color()

    // 任意のclassがsealed classの子クラスになれるので
    // data classでも良い。
    data class Rgb(val red: Int, val green, val blue): Color()
    data class Cmyk(val cyan: Int, val magenta: Int, val yellow: Int, val keyPlate: Int): Color()
}
상수뿐만 아니라 사용자 정의 값도 표시할 수 있다니.
편리하다!!

가치의 중첩을 표현하고 싶어요.


우리 깊이 생각해 봅시다.
Color류는 여러 상태가 겹치는 것으로 포착할 수 없습니까?
특히 데이터class 부분만 꺼내서 보세요.
sealed class Color {
    data class Rgb(val red: Int, val green, val blue): Color()
    data class Cmyk(val cyan: Int, val magenta: Int, val yellow: Int, val keyPlate: Int): Color()
}
이것도'Color는 색깔(표현법은 모르지만), 색깔의 표현법Rgb 또는Cmyk'이라고 읽을 수 있다.
형으로 이'또는'을 표현할 수 있는 것은 대수 데이터형이다.
이렇게 이해하면 표현할 수 있는 것들의 범위가 넓어질 것 같지 않아요?

예: 성공 또는 실패


처리된 결과를 호출자에게 되돌려주고 싶다면, 보통return을 사용합니다.

fun doSomeProc(): SomeData {

    ...

    // 結果を返す
    return someValue
}
만약 네가 자주 성공한다면 좋겠다.
그러면 실패한 경우는요?반환값이 Int 등이면 -1 이상값을 이상값으로 설정하는 경우도 있지만 자바의 세계에서는 예외를 던진다.

fun doSomeProc(): SomeData {

    ...

    // 失敗した場合は例外を投げて値を返さない
    if (failed) throw FailureException()

    return someValue
}
하지만 Kotlin은 검사 예외가 없습니다.
실수로 try-catch 를 잊어버리면 실행할 때 예외적인 프로그램도 붕괴될 수 있습니다.
그렇다면 성공과 실패를 가치로 표현해 보는 것은 어떨까?
sealed class Result<V>

data class Success<V>(val value: V): Result<V>()
data class Failure<V>(val reason: Exception): Result<V>()

fun doSomeProc(): Result<SomeData> {

    ...

    return if (failed) Failure(FailureException())
           else        Success(someValue)
}


val result = doSomeProc()
when (result) {
    // smart castしてます。便利。
    is Success -> println("data is ${result.value}")
    is Failure -> println("process failed because ${result.reason}")
}
이렇게 하면 성공할 때와 실패할 때의 행동을 명확하게 쓸 수 있다. is의 유형 검사가 없으면 안의 값을 꺼낼 수 없기 때문에 성공인지 실패인지 강제로 검사할 수 있다.
여러 명이 개발할 때 편리합니다!
네, 눈치채셨을 거예요. 이른바 에이더형이에요.
좋은 에이서의 설치는 map 등이 있고, 일일이 넣지 않아도 되기 때문에 실용적일 때 유지자가 공개한 라이브러리를 사용하는 것이 좋다.
  • adelnizamutdinov/kotlin-either
  • Kotlin도 generix의 하한경계 어댑터를 사용하고 싶습니다!!
  • (2019/04/02 추적)
    그러고 보니 Kotlin1.3부터 Kotlin-stdlib은 정식으로 Result형을 채택했다!
    편리한 전용 확장 함수 등도 정의되어 있으니 잘 사용하세요!
  • Result - Kotlin Programing Language
  • 예: 상태 관리


    성공과 실패, 두 개를 합칠 수 있다면 여러 상태도 합칠 수 있다.
    응용 프로그램의 화면에서 곤란한 것은 여러 개의 비동기 처리가 도망갈 수 있다는 것이다.
    예를 들어 데이터를 읽는 과정에서 또 읽기 이벤트가 발생하면...?when 또는 읽을 표지판은 무엇입니까?그러면 읽기 중인 상태의 디스플레이 테스트를 하려면 어떻게 해야 하나요?로고는 언제 설치합니까?
    만약 네가 이런 것들을 고려하기 시작한다면, 너의 머리는 펑크가 날 것이다.
    거기서 sealed class!
    응용 프로그램의 화면 상태를 관리하는 데도 사용할 수 있습니다!
    이것도 내가 사용하기에 매우 편리하고 sealedclass를 좋아하는 이유이다.
    // 何かのデータを読み込んで、それを表示する画面の状態管理クラス
    class SomeScreenModel(private val repo: Repository, initState: State = State.NoData) {
        sealed class State {
            // まだ読み込みしていない状態
            object NoData: State()
            // 読み込み中
            object Loading: State()
            // 読み込み正常終了
            data class Loaded(val hoge: String, val fuga: Int): State()
            // 読み込み失敗
            data class LoadFailure(val reason: Throwable): State()
        }
    
        // RxJavaのObservableや、JavaFXのObservableValueなどで変更を通知できるようにしておくと更に便利
    
        private val subject = BehaviorSubject.createDefault(initState)
    
        val stateChangeEvent: Observable<State>
            get() = subject
    
        var currentState: State
            get() = subject.value
    
        // 読み込む
        fun load() {
            // メンバのままだと値が変わる可能性がありsmart castが働かないので、一度取り出しておく
            val currentState = currentState
            // 読み込み中だったら無視
            if (currentState is State.Loading) return 
    
            subject.onNext(State.Loading)
    
            repo
                .load()
                .subscribe({ value ->
                    subject.onNext(State.Loaded(value.hoge, value.fuga))
                }, { e ->
                    // 例えば失敗を告げるダイアログだけ表示させてから
                    subject.onNext(State.LoadFailure(e))
                    // 未読み込み状態に戻るとか
                    subject.onNext(State.NoData)
                })
        }
    }
    
    이것만으로도 다음과 같은 내용을 실현할 수 있다.
  • 망라 화면이 얻을 수 있는 상태
  • 상태와 관련된 매개 변수를 유지할 수 있음
  • 화면이 현재 표시해야 할 상태 알기
  • 화면 상태가 바뀌면 이벤트가 날아온다
  • 임의의 상태에서 화면 표시를 시작할 수 있음
  • 특정 상태에서 수행할 수 없는 처리를 무시할 수 있음
  • 이후 이 반이 가진'화면 상태'를 보고 이 상태를 화면에 반영하는 반을 만들면 화면이 정의되지 않은 상태에 빠지지 않는다.
    화면 디버깅이 상당히 간단해졌다!
    안드로이드의 이런 상태 관리 방법은 이전 학습회에서 말했듯이 구체적인 설치 방법은 이쪽 슬라이드를 보십시오.
  • 화면 상태를 추상화하고 테스트 디자인 생활을 하세요.
  • 끝내다


    이러한 언어 기능 외에도 experimental의 Kotlin Android Extensions의 기능과 Kotlin/Native 등이 있어 Kotlin의 매력은 더욱 커질 것이다.
    내년에도 즐거운 Kotlin 생활 되세요!Have a nice kotlin!!

    좋은 웹페이지 즐겨찾기