독서

[코틀린 인 액션] 11. DSL 만들기

오렌지색 귤 2024. 6. 2. 10:47
반응형

1. 함수타입을 확장하면서 INVOKE()를 오버라이딩하는 예제

 

Kotlin Coroutines

 

코틀린 코루틴 라이브러리에서는 Continuation이라는 인터페이스가 있는데, 이 인터페이스는 비동기 작업의 결과를 처리하는 데 사용됩니다. Continuation 인터페이스는 resumeWith이라는 메서드를 가지고 있지만, 이를 invoke를 통해 간단하게 호출할 수 있습니다.

 

interface Continuation<T> {
    fun resumeWith(result: Result<T>)
}

class PrintContinuation<T> : Continuation<T> {
    override fun resumeWith(result: Result<T>) {
        println(result.getOrNull())
    }
}

fun main() {
    val continuation = PrintContinuation<String>()
    continuation.resumeWith(Result.success("Hello, Coroutines!")) // Output: Hello, Coroutines!
}

 

위 예제에서 Continuation 인터페이스를 구현한 PrintContinuation 클래스가 resumeWith 메서드를 오버라이딩하여 결과를 출력합니다. 이 예제를 invoke로 바꿔 보겠습니다.

 

interface Continuation<T> {
    operator fun invoke(result: Result<T>)
}

class PrintContinuation<T> : Continuation<T> {
    override fun invoke(result: Result<T>) {
        println(result.getOrNull())
    }
}

fun main() {
    val continuation = PrintContinuation<String>()
    continuation(Result.success("Hello, Coroutines!")) // Output: Hello, Coroutines!
}

 

invoke를 사용하면 resumeWith 대신 continuation(result) 형태로 호출할 수 있어 코드가 더 간결해집니다.

 

 

 

2. 그럼 굳이 함수가 아닌 클래스 + invoke 오버라이딩을 사용하는 이유

 

- 코드 간결성

 

invoke를 사용하면 함수 호출과 유사하게 객체를 사용할 수 있어 코드가 더 읽기 쉽고 간결해진다

 

- 함수형 프로그래밍 스타일

 

함수 객체를 함수처럼 사용할 수 있어 함수형 프로그래밍 스타일을 유지하면서 객체 지향 프로그래밍의 장점을 활용할 수 있다

 

- 캡슐화와 유연성

 

invoke를 오버라이딩하면 호출 방식의 캡슐화가 가능해지고, 다양한 호출 패턴을 유연하게 정의할 수 있습니다. 예를 들어, 추가적인 로직을 invoke 메서드에 포함시킬 수 있다

 

 

 

3. 멤버 확장

 

멤버 확장(Extension)은 코틀린의 강력한 기능 중 하나로, 기존 클래스에 새로운 메서드나 프로퍼티를 추가하는 기능을 의미합니다. 이를 통해 기존 클래스의 소스를 수정하지 않고도 클래스의 기능을 확장할 수 있습니다.

멤버 확장에는 크게 두 가지 유형이 있습니다:

  1. 함수 확장(Extension Functions)
  2. 프로퍼티 확장(Extension Properties)

 

함수 확장(Extension Functions)

 

함수 확장은 기존 클래스에 새로운 메서드를 추가하는 것을 의미합니다. 예를 들어, String 클래스에 새로운 메서드를 추가하고 싶을 때 사용합니다.

 

fun String.lastChar(): Char {
    return this[this.length - 1]
}

fun main() {
    val str = "Hello"
    println(str.lastChar()) // Output: o
}

 

위 예제에서 String 클래스에 lastChar라는 확장 함수를 추가했습니다. 이제 String 객체에서 lastChar 메서드를 호출할 수 있습니다.

 

 

프로퍼티 확장(Extension Properties)

 

프로퍼티 확장은 기존 클래스에 새로운 프로퍼티를 추가하는 것을 의미합니다. 확장 프로퍼티는 실제로 상태를 저장하지 않으며, 게터(및 필요한 경우 세터)를 통해 값을 계산합니다.

 

val String.lastChar: Char
    get() = this[this.length - 1]

fun main() {
    val str = "Hello"
    println(str.lastChar) // Output: o
}

 

위 예제에서 String 클래스에 lastChar라는 확장 프로퍼티를 추가했습니다. 이제 String 객체에서 lastChar 프로퍼티를 접근할 수 있습니다.

반응형