Kotlin/Effective Kotlin 요약
-
36장 - 상속보다는 컴포지션을 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 25. 00:01
개요 상속은 is-a 관계의 객체 계층 구조를 만들기 위해 설계되었습니다. 코드의 재사용성을 위해 상속을 사용할 때 관계가 명확하지 않을 때 신중하게 고려해야 합니다. 간단한 행위 재사용 class ProfileLoader{ fun load(){ //프로그래스 바 노출 //프로필 읽기 //프로그래스 바 숨김 } } class ImageLoader{ fun load(){ //프로그래스 바 노출 //이미지 읽기 //프로그래스 바 숨김 } } 이런 경우 보통 슈퍼클래스를 만들어 공통되는 행위를 뽑아냅니다. 하지만 몇 가지 단점이 존재합니다. 상속을 사용해서 행위를 추출하다 보면, 많은 함수를 갖는 거대한 BaseXXX 클래스가 만들어지며 깊고 복잡한 계층 구조가 만들어집니다. 불필요한 함수를 갖는 클래스가 만..
-
35장 - 복잡한 객체를 생성하기 위한 DSL을 정의하라Kotlin/Effective Kotlin 요약 2023. 3. 21. 00:01
코틀린을 활용하면 DSL을 직접 만들 수 있습니다. DSL을 만드는 것은 수고스러우나, 한 번 만들고 나면 보일러플레이트와 복잡성을 숨기면서 개발자의 의도를 명확하게 표현할 수 있습니다. Spring Kotlin개발자에게는 다음과 같은 DSL이 친숙할 수 있습니다. Kotest를 활용하여 테스트 케이스를 정의할 때 Gradle의 설정을 정의할 때 사용자 정의 DSL 만들기 DSL을 만들기 전 리시버를 사용하는 함수 타입에 대한 개념을 이해해야 합니다. 람다식을 떠올리면 좋으며 함수 타입의 몇 가지 예시입니다. () -> Unit 아규먼트를 갖지 않고 Unit을 리턴 (Int, Int) -> Int Int타입 아규먼트 2개를 받고, Int를 리턴하는 함수 함수 타입을 만드는 기본적인 방법들 람다 표현식 익..
-
34장 - 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 20. 00:01
객체를 생성하고 사용하는 가장 기본적인 방법 class User(var name: Stirng, var surname: String) val user = User("Marcin", "Moskala") 이처럼 객체의 초기 상태를 나타내는 아규먼트를 전달합니다. 데이터 모델 객체 data class Student( val name: String, val surname: String, val age: Int, ) 하지만 생성자에 선언된 아규먼트 이외에도 클래스의 필드로도 프로퍼티를 가질 수 있습니다. 이럴 때는 어떻게든 초기화된 되면 상관없습니다. 일반적으로 기본생성자가 제일 좋은 방식인 이유를 이해하려면, 점층적 생성 패턴과 빌더 패턴에 대해 이해하는 것이 좋습니다. 점층적 생성 패턴 class Pizza{..
-
33장 - 생성자 대신 팩토리 함수를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 19. 00:01
클라이언트가 클래스의 인스턴스를 만들게 하는 다양한 방법을 알아보겠습니다. 가장 일반적인 방법 - 생성자 class MyLinkedList{ val head: T, val tail: MyLinkedList? } val list = MyLinkedList(1, MyLinkedList(2, null)) 하지만 굉장히 다양한 생성 패턴이 존재하며, 별도의 함수를 통해 생성할 수 있습니다. 팩토리 함수 fun myLinkedListof( vararg elements: T ): MyLinkedList? { if(elements.isEmpty()) return null val head = elements.first() val elementsTail = elements.copyOfRange(1, elements.si..
-
32장 - 추상화 규약을 지켜라Kotlin/Effective Kotlin 요약 2023. 3. 18. 00:01
규약과 위반 규약은 개발자들의 단순한 합의에 불과합니다. 따라서 한쪽에서 규약을 위반할 수도 있습니다. 간단한 예시로 리플렉션을 활용하면 private property의 값을 변경할 수 있습니다. 하지만 이를 위반하면 안 됩니다. 프로젝트에서 규약을 위반하는 경우 이는 내부에 시한폭탄을 설치한 것과 같습니다. 상속된 규약 모든 클래스는 equals와 hashCode 메서드를 가진 Any 클래스를 상속받습니다. 이러한 메서드는 모든 우리가 반드시 존중하고 지켜야 하는 규약을 갖고 있습니다. 이를 지키지 않는다면 HashSet과 함께 사용할 때 제대로 동작하지 않을 수 있습니다.
-
31장 - 문서로 규약을 정의하라Kotlin/Effective Kotlin 요약 2023. 3. 17. 00:01
아이템 27에서 추상화를 통해 메시지를 출력하는 함수를 만들었습니다. fun Context.showMessage( message: String, duration: MessageLength = MessageLength.Long ){ val toastDuration = when(duration){ SHORT -> LENGTH.LENGTH_SHORT LONG -> LENGTH.LENGTH_LONG } Toast.makeText(this, message, toastDuration).show() } enum class MessageLength {SHORT, LONG} 이때 showMessage라는 함수이름을 통해 토스트가 아니라 다른 타입으로도 출력할 수 있도록 이름을 붙였습니다. 하지만 다른 개발자는 이 코드를..
-
30장 - 요소의 가시성을 최소화하라Kotlin/Effective Kotlin 요약 2023. 3. 16. 00:01
가시성과 클래스 클래스는 만족해야 하는 상태에 대한 규약들이 존재합니다. 이런 규약을 모르는 사람은 클래스의 상태를 마음대로 변경할 수 있습니다. 이렇게 되면 클래스의 불변성이 무너질 가능성이 있습니다. 일반적으로 코틀린에서는 구체 접근자의 가시성을 제한해서 모든 프로퍼티를 캡슐화하는 것이 좋습니다. 가시성이 제한될 수록 클래스의 변경을 쉽게 추적할 수 있으며, 프로퍼티의 상태를 더 쉽게 이해할 수 있습니다. 이로 인해 동시성을 처리할 때도 더 안전해집니다. 가시성 한정자 - public(디폴트) : 어디에서나 볼 수 있음 - private : 클래스 내부에서만 볼 수 있음 - protected : 클래스와 서브클래스 내부에서만 볼 수 있음 - internal : 모듈 내부에서만 볼 수 있음 예를 들어 ..
-
29장 - 외부 API를 랩해서 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 15. 00:01
외부 API를 warp 해서 사용하면 얻는 자유와 안정성 - 문제가 있다면 래퍼만 변경하면 되어, API 변경에 쉽게 대응할 수 있다 - 프로젝트 스타일에 맞춰 API의 형태를 조정할 수 있다 외부 API를 warp해서 얻는 단점 - 래퍼를 따로 정의해야 한다. - 래퍼는 프로젝트 내부에서만 유효하며, 어떤 래퍼들이 존재하는지 따로 확인해야 한다 결론 장단점을 잘 이해하고 라이브러리가 얼마나 안정적인지, 사용자에게 인기가 많은지에 따라 API를 랩 할지 말지 잘 결정해야 합니다. 만약 인기가 없고 새로 만들어진 라이브러리라면 신중하게 사용을 결정하고, 사용하기로 했다면 클래스와 함수로 랩 하는 것을 고려하기 바랍니다.