일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드 라이선스 종류
- 멤버변수
- rxjava cold observable
- jvm 작동 원리
- 서비스 쓰레드 차이
- 안드로이드 유닛 테스트 예시
- 서비스 vs 쓰레드
- 안드로이드 유닛테스트란
- 큐 자바 코드
- 플러터 설치 2022
- 스택 큐 차이
- 자바 다형성
- 안드로이드 os 구조
- ANR이란
- 안드로이드 라이선스
- 2022 플러터 안드로이드 스튜디오
- 객체
- 스택 자바 코드
- jvm이란
- 안드로이드 유닛 테스트
- Rxjava Observable
- 클래스
- 안드로이드 레트로핏 사용법
- rxjava hot observable
- 2022 플러터 설치
- android retrofit login
- android ar 개발
- 안드로이드 레트로핏 crud
- rxjava disposable
- ar vr 차이
- Today
- Total
나만을 위한 블로그
[이펙티브 코틀린] 아이템 38. 연산 또는 액션을 수행할 때 인터페이스 대신 함수 타입을 사용하라 본문
[이펙티브 코틀린] 아이템 38. 연산 또는 액션을 수행할 때 인터페이스 대신 함수 타입을 사용하라
참깨빵위에참깨빵_ 2023. 3. 3. 00:09대부분 프로그래밍 언어에는 함수 타입이란 개념이 없어서 연산 또는 액션을 전달할 때 메서드가 하나만 있는 인터페이스를 활용한다. 이런 인터페이스를 SAM(Single-Abstract Method)이라고 부른다. 예를 들어 아래 코드는 뷰를 클릭했을 때 발생하는 정보를 전달하는 SAM이다.
interface OnClick {
fun clicked(view: View)
}
함수가 SAM을 받는다면 이런 인터페이스를 구현한 객체를 구현한 객체를 전달받는다는 의미다.
fun main() {
setOnClickListener(object: OnClick {
override fun clicked(view: View) {
// ...
}
})
}
fun setOnClickListener(listener: OnClick) {
// ...
}
이런 코드를 함수 타입을 쓰는 코드로 바꾸면 더 많은 자유를 얻을 수 있다.
fun setOnClickListener(listener: (View) -> Unit) {
// ...
}
예를 들어 아래 같은 방법으로 파라미터를 전달할 수 있다.
- 람다식 또는 익명 함수로 전달
setOnClickListener { /* ... */ }
setOnClickListener(fun(view) { /* ... */ })
- 함수 레퍼런스 또는 제한된 함수 레퍼런스로 전달
setOnClickListener(::println)
setOnClickListener(this::showUsers)
- 선언된 함수 타입을 구현한 객체로 전달
fun main() {
setOnClickListener(ClickListener())
}
class ClickListener: (View) -> Unit {
override fun invoke(view: View) {
// ...
}
}
이런 방법들은 광범위하게 쓰인다. SAM의 장점은 '그 아규먼트에 이름이 붙어있는 것'이라고 하는 사람도 있다. 하지만 타입 별칭(typealias)을 쓰면 함수 타입도 이름을 붙일 수 있다.
typealias OnClick = (View) -> Unit
파라미터도 이름을 가질 수 있다. 이름을 붙이면 IDE의 지원을 받을 수 있다는 큰 장점이 있다.
fun setOnClickListener(listener: OnClick) { /* ... */ }
typealias OnClick = (view: View) -> Unit
람다식을 사용할 때는 아규먼트 분해(destructure argument)도 쓸 수 있다. 이건 SAM보다 함수 타입을 쓰는 게 훨씬 더 좋은 이유다.
여러 옵저버를 설정할 때 이 장점을 확인할 수 있다. 고전적인 자바는 아래처럼 인터페이스를 기반으로 구현했다.
class CalendarView {
var listener: Listener? = null
interface Listener {
fun onDateClicked(date: Date)
fun onPageChanged(date: Date)
}
}
API를 소비하는 사용자 관점에선 함수 타입을 따로 갖는 게 훨씬 쓰기 쉽다.
class CalendarView {
var onDateClicked: ((date: Date) -> Unit)? = null
var onPageClicked: ((date: Date) -> Unit)? = null
}
이렇게 onDateClicked, onPageChanged를 한꺼번에 묶지 않으면 각각의 것을 독립적으로 바꿀 수 있다는 장점이 생긴다. 인터페이스를 써야 하는 특별한 이유가 없다면 함수 타입을 활용하는 게 좋다. 함수 타입은 다양한 지원을 받을 수 있으며 코틀린 개발자들 사이에서 널리 쓰이고 있다.
언제 SAM을 써야 하는가?
코틀린이 아닌 다른 언어에서 사용할 클래스를 설계할 때 SAM을 쓰는 게 좋다. 자바에선 인터페이스가 더 명확하다. 함수 타입으로 만들어진 클래스는 자바에서 타입 별칭과 IDE의 지원 등을 제대로 받을 수 없다. 마지막으로 다른 언어(자바 등)에서 코틀린의 함수 타입을 사용하려면 Unit을 명시적으로 리턴하는 함수가 필요하다.
자바에서 사용하기 위한 API를 설계할 때는 함수 타입보다 SAM을 쓰는 게 합리적이다. 이외의 경우에는 함수 타입을 쓰는 게 좋다.
'책 > Effective Kotlin' 카테고리의 다른 글
[이펙티브 코틀린] 아이템 40. equals의 규약을 지켜라 (0) | 2023.03.19 |
---|---|
[이펙티브 코틀린] 아이템 39. 태그 클래스보다는 클래스 계층을 사용하라 (0) | 2023.03.13 |
[이펙티브 코틀린] 아이템 37. 데이터 집합 표현에 class 한정자를 사용하라 (0) | 2023.02.26 |
[이펙티브 코틀린] 아이템 36. 상속보다는 컴포지션을 사용하라 (0) | 2023.02.02 |
[이펙티브 코틀린] 아이템 35. 복잡한 객체를 생성하기 위한 DSL을 정의하라 (0) | 2023.01.31 |