728x90
반응형
✅ 컴파일러가 생성한 메서드 : 데이터 클래스와 클래스 위임
- 자바에서는 클래스가 equals, hashCode, toString과 같이 기계적으로 구현할 수 있는 메서드들이 존재
- 하지만 코틀린에서는 한걸음 더 나가서 이러한 메서드를 기계적으로 생성하는 작업을 보이지 않는 곳에서 해줌
- 따라서 필수 메서드로 인한 잡음 없이 소스코드를 깔끔하게 유지할 수 있음
📌 모든 클래스가 정의해야 하는 메서드 자동 생성
- 자바와 마찬가지로 코틀린 클래스도 toString, equals, hashCode 등을 오버라이드하여 사용할 수 있음
- 만약 어떤 클래스가 데이터를 저장하는 역할만을 수행한다면 위의 메서드들을 반드시 오버라이드해야 함
- IDE에서 자동으로 메서드들을 정의해주고, 작성된 메서드의 정확성과 일관성을 검사해줌
- 하지만 코틀린에서는 data 변경자를 붙여주기만 하면 equals, hashCode, toString등의 메소드를 컴파일러가 자동으로 만들어줌
data class Client(val name: String, val postalCode: Int)
- 인스턴스 간 비교를 위한 equals
- HashMap과 같은 해시 기반 컨테이너에서 키로 사용할 수 있는 hashCode
- 클래스의 각 필드를 선언 순서대로 표시하는 문자열 표현을 만들어주는 toString
📌 데이터 클래스와 불변성 : copy() 메서드
- 데이터 클래스의 모든 프로퍼티를 읽기 전용으로 만들어서 데이터 클래스를 불변 클래스로 만들라고 권장함
- HashMap 등의 컨테이너에 데이터 클래스 객체를 담는 경우엔 불변성이 필수적
- 데이터 클래스 인스턴스를 불변 객체로 더 쉽게 활용할 수 있게 코틀린 컴파일러는 한 가지 편의 메서드를 제공함
- 그 메서드는 객체를 복사하면서 일부 프로퍼티를 바꿀 수 있게 해주는 copy 메서드임
- 복사본은 원본과 다른 생명주기를 가지며, 복사를 하면서 일부 프로퍼티 값을 바꾸거나 복사본을 제거해도 프로그램에서 원본을 참조하는 다른 부분에 전혀 영향을 끼치지 않음
class Client(val name: String, val postalCode: Int) {
...
fun copy(name: String = this.name, postalCode: Int = this.postalCode) = Client(name, postalCode)
}
val lee = Client("이계영", 4122)
println(lee.copy(postalCode = 4000)) // Client(name=이계영, postalCode=4000)
📌 클래스 위임 : by 키워드 사용
- 종종 상속을 허용하지 않는 클래스에 새로운 동작을 추가해야 할 때가 있음
- 이럴 때 사용하는 일반적인 방법은 데코레이터 패턴을 활용하는 것
- 이 패턴의 핵심은 상속을 허용하지 않는 클래스 대신 사용할 수 있는 새로운 클래스를 만들되 기존 클래스와 같은 인터페이스를 데코레이터가 제공하게 만들어, 기존 클래스를 데코레이터 내부에 필드로 유지하는 것
- 이 접근의 단점은 준비 코드가 상당히 많이 필요하다는 점
class DelegatingCollection<T> : Collection<T> {
private val innerList = arrayListOf<T>()
override val size: Int get() = innerList.size
override val isEmpty() : Boolean = innerList.isEmpty()
override val contains(element: T): Boolean = innerList.contains(element)
override val iterator(): Iterator<T> = innerList.iterator()
override val containsAll(elements): Boolean =
innerList.containsAll(elements)
}
- 하지만 코틀린에서는 by 키워드를 통해 그 인터페이스에 대한 구현을 다른 객체에 위임 중이라는 사실을 명시할 수 있음
class CountingSet<T>(
val innerSet: MutableCollection<T> = HashSet<T>()
) : MutableCollection<T> by innerSet {
var objectsAdded = 0
override fun add(element: T): Boolean {
objectsAdded++
return innerSet.add(element)
}
override fun addAll(c: Collection<T>): Boolean {
objectsAdded += c.size
return innerSet.addAll(c)
}
}
- add와 addAll을 오버라이드해서 카운터를 증가시키고, MutableCollection 인터페이스의 나머지 메서드는 내부 컨테이너에게 위임
728x90
반응형
'Studying > Kotlin' 카테고리의 다른 글
[Kotlin In Action] 5장. 람다로 프로그래밍(1) - 람다 식과 멤버 참조 (0) | 2023.05.17 |
---|---|
[Kotlin In Action] 4장. 클래스, 객체, 인터페이스(4) - object 키워드 : 클래스 선언과 인스턴스 생성 (0) | 2023.05.16 |
[Kotlin] 코틀린의 Scope Function(범위 지정 함수) (0) | 2023.05.16 |
[Kotlin In Action] 4장. 클래스, 객체, 인터페이스(2) - 뻔하지 않은 생성자와 프로퍼티를 갖는 클래스 선언 (2) | 2023.05.11 |
[Kotlin In Action] 4장. 클래스, 객체, 인터페이스(1) - 클래스 계층 정의 (0) | 2023.05.09 |