반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

안드로이드 개발자 노트

[이펙티브 코틀린] Item38. 연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라 본문

Kotlin/이펙티브 코틀린

[이펙티브 코틀린] Item38. 연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라

어리둥절범고래 2023. 12. 31. 12:51
반응형

대부분의 프로그래밍 언어에는 함수 타입이 없어서 연산 또는 액션을 전달할 때 메서드가 하나만 있는 인터페이스를 활용합니다.

이러한 인터페이스를 SAM(Single-Abstract Method)이라고 부릅니다.

함수가 SAM을 받는다면, 이러한 인터페이스를 구현한 객체를 전달받는다는 의미입니다.

예를 들어 다음 코드는 뷰를 클릭했을 때 발생하는 정보를 전달하는 SAM입니다.

interface OnClick {
    fun clicked(view: View)
}

fun setOnclickListener(listener: Onclick) {
    // ...
}

setOnClickListener(object: Onclick {
    override fun clicked(view: View) {
        // ...
    }
})

 

함수 타입을 사용하는 코드로 변경하면 다음과 같습니다.

fun setOnClickListener(listener: (View) -> Unit) {
    // ...
}

이렇게 하면 더 많은 자유를 얻을 수 있으며, 다음과 같은 방법으로 파라미터를 전달할 수 있습니다.

// 람다 표현식 또는 익명 함수로 전달
setOnClickListener { /* ... */ }
setOnClickListener(fun(view) { /* ... */ })

// 함수 레퍼런스 또는 제한된 함수 레퍼런스로 전달
setOnClickListener(::println)
setOnClickListener(this::showUsers)

// 선언된 함수 타입을 구현한 객체로 전달
class ClickListener: (View)->Unit {
	override fun invoke(view: View) {
		// ...
	}
}

 

타입 별칭(type aliase)을 사용하면, 함수 타입도 이름을 붙일 수 있습니다.

typealias OnClick = (View) -> Unit

 

파라미터도 이름을 가질 수 있습니다.

이름을 붙이면, IDE의 지원을 받을 수 있다는 장점이 있습니다.

fun setOnClickListener(listener: OnClick) { /*...*/ }
typealias OnClick = (view: View, id: Int)->Unit

 

람다 표현식을 사용할 때는 아규먼트 분해(destructure argument)도 사용할 수 있습니다.

고전적인 자바는 다음과 같이 인터페이스를 기반으로 구현했습니다.

class CalendarView {
    var listenr: Listener? = null
    
    interface Listener {
        fun onDateClicked(date: Date)
        fun onPageChanged(date: Date)
    }
}

함수 타입을 따로따로 갖는 것이 훨씬 사용하기 쉬우며, 각각의 것을 독립적으로 변경할 수 있습니다.

class CalendarView {
    fun onDateClicked((date: Date) -> Unit)? = null
    fun onPageChanged((date: Date) -> Unit)? = null
}

 

 

딱 한 가지 경우에만 SAM을 사용하는 것이 좋습니다.

코틀린이 아닌 다른 언어에서 사용할 클래스를 설계할 때입니다.

함수 타입으로 만들어진 클래스는 자바에서 타입 별칭과 IDE의 지원을 받을 수 없으며, Unit을 명시적으로 리턴하는 함수가 필요합니다.

// 코틀린
class CalendarView() {
    var onDateClicked: ((date: Date) -> Unit)? = null
    var onPageChanged: OnDateClicked? = null
}

interface onDateClicked {
    fun onClick(date: Date)
}

// 자바
CalendarView c = new CalendarView();
c.setOnDateClicked(date -> Unit.INSTANCE);
c.setOnPageChanged(date -> {});
반응형