안드로이드 개발자 노트
[이펙티브 코틀린] Item43. API의 필수적이지 않는 부분을 확장 함수로 추출하라 본문
반응형
클래스의 메서드를 정의할 때는 멤버로 정의할 것인지 확장 함수로 정의할 것인지 결정해야 합니다.
// 멤버로 메서드 정의하기
class Workshop(/*...*/) {
//...
fun makeEvent(date: DateTime): Event = //...
val permalink
get() = "/workshop/$name"
}
// 확장 함수로 메서드 정의하기
class Workshop(/*...*/) {
//...
}
fun Workshop.makeEvent(date: DateTime): Event = //...
val Workshop.permalink
get() = "/workshop/$name"
멤버와 확장의 차이점
- 확장은 따로 가져와서 사용해야 한다.
- 확장은 우리가 직접 멤버 변수를 추가할 수 없는 경우 데이터와 행위를 분리하도록 설계된 프로젝트에서 사용된다.
- 필드가 있는 프로퍼티는 클래스에 있어야 하지만, 확장 메서드는 클래스의 public API만 활용하면 어디에 위치해도 상관없다.
- import 해서 사용하기 때문에 같은 타입에 같은 이름으로 여러 개 만들 수도 있어, 여러 라이브러리에서 여러 메서드를 받을 수도 있고 충돌이 발생하지 않는다는 장점이 있다.
- 같은 이름인데 다른 동작을 한다면 리스크가 생길 수 있으니, 그냥 멤버 함수로 만드는게 나을 수도 있다.
- 확장은 가상(virtual)이 아니다.
- 그래서 서브 클래스에서 오버라이드 할 수 없다.
- 확장 함수는 컴파일 시점에 정적으로 선택되기 때문에 확장 함수는 가상 멤버 함수와 다르게 동작한다.
- 따라서 상속을 목적으로 설계된 요소는 확장 함수로 만들면 안된다.
- 확장 함수는 클래스 레퍼런스에 나오지 않는다.
- 그래서 확장 함수는 어노테이션 프로세서가 따로 처리하지 않는다.
- 따라서 필수적이지 않는 요소를 확장 함수를 추출하면 어노테이션 프로세서로부터 숨겨진다.
- 이는 확장 함수가 클래스 내부에 있는 것이 아니기 때문이다.
- 확장 함수는 클래스 위가 아니라 타입 위에 만들어진다.
- 그래서 nullable 또는 구체적인 제너릭 타입에도 확장함수를 정의할 수 있음
// nullble 타입에 확장함수 정의 가능
inline fun CharSequence?.isNullOrBlank(): Boolean {
contract {
returns(false) implies (this@isNullOrBlank != null)
}
return this == null || this.isBlank()
}
// 구체적인 제너릭 타입에 확장함수 정의 가능
public fun Iterable<Int>.sum(): Int {
var sum :Int = 0
for (element in this) {
sum += element
}
return sum
}
정리
- 확장 함수는 더 많은 자유와 유연성을 준다.
- 확장 함수는 상속, 어노테이션 처리 등을 지원하지 않고, 클래스 내부에 없으므로 약간 혼동을 줄 수도 있다.
- API의 필수적인 부분은 멤버로 두는 것이 좋다.
- 필수적이지 않은 부분은 확장 함수로 만드는 것이 좋다.
반응형
'Kotlin > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item44. 멤버 확장 함수의 사용을 피하라 (0) | 2024.01.14 |
---|---|
[이펙티브 코틀린] Item42. compareTo의 규약을 지켜라 (0) | 2024.01.13 |
[이펙티브 코틀린] Item41. hashCode의 규약을 지켜라 (0) | 2024.01.13 |