본문 바로가기

Kotlin

[Kotlin] SAM & invoke

served by pixabay

안녕하세요.

오늘은 SAM (Single Abstract Method) 과 invoke에 대해서 알아보겠습니다.

SAM과 invoke는 함수형 프로그래밍을 더 간결하고 쉽게 작성하기 위해 지원하는 기능입니다.


SAM (Single Abstract Method)

하나의 추상 메서드만 포함하는 인터페이스를 SAM 이라고 합니다

 

추상 메서드를 하나만 포함하는 클릭 리스너를 만들어 보겠습니다

interface OnClickListener {
    fun onClick()
}

 

해당 인터페이스를 쓰는 예시입니다

val listener = object : OnClickListener {
    override fun onClick() {
        println("Clicked")
    }
}

listener.onClick()  // 출력: Clicked

 

SAM은 이 코드를 아래와 같이 사용할 수 있습니다

val listener = OnClickListener { println("Clicked") }

listener.onClick()  // 출력: Clicked

 

그렇지만, 이는 에러 코드입니다.

 

추가 작업을 해줘야 합니다.


functional interface

함수형 인터페이스 입니다

코틀린에서 SAM 변환을 지원하기 위해선 fun interface 키워드를 사용해야 합니다

fun interface OnClickListener {
    fun onClick()
}

val listener = OnClickListener { println("Clicked") }

listener.onClick()  // 출력: Clicked

 

성공적으로 실행되는 것을 확인할 수 있습니다


invoke

invoke 기능을 활용하면

객체를 함수처럼 호출할 수 있습니다

class Greeter {
    operator fun invoke(name: String) = "Hello, $name!"
}

fun main() {
    val greeter = Greeter()
    println(greeter("Kotlin")) // invoke를 사용하여 함수처럼 호출
}

사용 예제

1) SAM 활용 : 콜백 처리

SAM 변환은 주로 콜백 함수나 리스너 인터페이스를 간단하게 사용할 때 유용합니다

// 인터페이스 (예: 콜백용)
fun interface ResponseCallback {
    fun onResponse(result: String)
}

// 네트워크 요청 함수 예시
fun performNetworkRequest(callback: ResponseCallback) {
    // 네트워크 작업을 수행한 후 콜백 호출
    callback.onResponse("Success")
}

fun main() {
    // SAM 변환을 통해 콜백을 람다로 간단하게 구현
    performNetworkRequest { result -> println("Network request completed with: $result") }
}

 

 

2) invoke 활용 : DSL 구현

DSL은 Domain Specific Language의 줄임말입니다

특정 도메인에 국한해 사용하는 언어입니다

class UserConfig {
    var username: String = ""
    var age: Int = 0
    fun printConfig() {
        println("UserConfig(username='$username', age=$age)")
    }
}

class ConfigDSL {
    private val userConfig = UserConfig()

    // invoke를 통해 DSL을 실행할 수 있도록 설정
    operator fun invoke(action: UserConfig.() -> Unit): UserConfig {
        userConfig.action()
        return userConfig
    }
}

fun main() {
    val config = ConfigDSL()

    // DSL을 사용해 사용자 설정 정의
    config {
        username = "Alice"
        age = 30
    }.printConfig() // 출력: "UserConfig(username='Alice', age=30)"
}

 

 

3) SAM과 invoke의 결합 : 함수형 프로그래밍

SAM과 invoke를 함께 사용하면, 중간 처리 단계에서 사용되는 변환 로직을 설정할 때 유용합니다

// 단계별 데이터 처리 인터페이스
fun interface DataProcessor {
    fun process(data: String): String
}

// 파이프라인을 구성하는 Processor 객체
class ProcessorPipeline {
    private val processors = mutableListOf<DataProcessor>()

    // invoke를 활용해 파이프라인 추가
    operator fun invoke(processor: DataProcessor) {
        processors += processor
    }

    fun execute(data: String): String {
        return processors.fold(data) { acc, processor -> processor.process(acc) }
    }
}

fun main() {
    val pipeline = ProcessorPipeline()

    // SAM 변환으로 데이터 처리 파이프라인 설정
    pipeline { it.uppercase(Locale.getDefault()) }
    pipeline { "$it!" }

    // 파이프라인 실행
    println(pipeline.execute("hello"))  // 출력: "HELLO!"
}

 

'Kotlin' 카테고리의 다른 글

[Kotlin] DSL (Domain Specific Language)  (0) 2024.11.05
[Kotlin] 함수형 프로그래밍  (2) 2024.10.29
[Kotlin] Scope Function  (2) 2024.10.11
[Kotlin] Sealed Class  (3) 2024.09.22
[Kotlin] Extension Function (확장 함수)  (0) 2024.09.10