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

woga·2023년 10월 14일
0

코틀린 공부

목록 보기
41/54
post-thumbnail

대부분의 프로그래밍 언어에는 함수 타입이라는 개념이 없다. 그래서 메서드가 하나만 있는 인터페이스를 활용하는데 이러한 인터페이스를 SAM(Single-Abstract Method)라고 부른다

ex)

interface OnClick {
	fun clicked(view: View)
}

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

fun setOnClickListener(listener: OnClick) {
	//...
}

setOnClickListener(object: OnClick {
	ovveride fun clicked(view: View) {
    	//..
    }
}

이런 코드를 함수 타입을 사용하는 코드로 변경하면 좋다.

fun setOnClickListener(listener: (View) -> Unit) {
	//...
}
  • 람다 표현식 또는 익명 함수로 전달
setOnClickListener { /*...*/ }
setOnClickListener(fun(view) { /*...*/ })
  • 함수 레퍼런스 또는 제한된 함수 레퍼런스로 전달
setOnClickListener(::println)
setOnClickListener(this::showUsers)
  • 선언된 함수 타입을 구현한 객체로 전달
class ClickListener: (View)->Unit {
	ovveride fun invoke(view: View) {
    	//...
    }
}

setOnClickListener(ClickListener())

이런 방법들은 광범위하게 사용된다.
아래와 같이 타입 별칭을 사용해서 함수 타입도 이름을 붙일 수 있다

typealias OnClick = (View) -> Unit

파라미터도 이름을 가질 수 있다. 이름을 붙이면 IDE 지원도 가능하다

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

람다 표현식을 사용할 때 아규머트 분해도 사용할 수 있다. 이것도 SAM보다 함수 타입을 사용하는 것이 훨씬 더 좋은 이유다.

여러 옵저버를 설정할 때 이 장점을 확인할 수 있고 자바에서는 인터페이스 기반으로 구현했지만 함수 타입을 따로 따로 갖는 것이 훨씬 사용하기 좋다

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

이렇게 한 꺼번에 묶지 않으면 각각의 것을 독립적으로 변경할 수 있다는 장점이 생긴다. 그래서 인터페이스를 사용해야하는 특별한 이유가 없다면 함수 타입을 활용하는 것이 좋다.
함수 타입은 다양한 지원을 받을 수 있으며 코틀린 개발자들 사이에서 이미 널리 사용되고 있다.

언제 SAM을 사용할까?

  • 코틀린이 아닌 다른 언어에서 사용할 클래스를 설계할 때 쓰자

자바에서는 인터페이스가 더 명확하다.
함수타입으로 만들어진 클래스는 자바에서 타입 별칭과 IDE의 지원 등을 제대로 받을 수 없다.

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

interface OnDateClicked {
	fun onClick(date: Date)
}
//java
CalendarView c = new CalendarView();
c.setOnDateClicked(date -> Unit.INSTANCE);
c.setOnPageChanged(date -> {});

자바에서 사용하기 위한 API를 설계할 때는 함수 타입 보단 SAM을 사용하자. 그리고 이외의 경우에는 함수 타입을 사용하자!

profile
와니와니와니와니 당근당근

0개의 댓글