클래스 위임
- 특정 클래스에 자기 클래스가 할 일을 다른 클래스에 맡겨 처리하는 것을 말한다.
- 위임을 맡기는 클래스를 위탁자, 위임을 받아서 실제 처리하는 클래스를 수탁자라고 한다.
- 코틀린에서는 이 관계를 by를 사용해서 쉽게 구성할 수 있다.
위임이 좋은 것은 다양한 기능을 하나의 클래스를 통해서 받고 처리할 수 있도록 구조화할 수 있기 때문이다.
동일한 일을 나눠서 처리하려면 공통된 인터페이스가 필요하다.
클래스 위임 처리
//같은 결과를 반환하는 두 case
val b = BaseImpl(10)
Derived(b).say()
class Derived_() : Base by BaseImpl(10)
Derived_().say()
//베이스 클래스 구현 : 10
//베이스 클래스 구현 : 10
생성자의 매개변수 속성으로 위임 처리
val ps = Person("사람") // Person은 인터페이스 Sayable을 상속받는 클래스
val pt = Pet("개") // Pet은 인터페이스 Sayable을 상속받는 클래스
class Saying(val say : Sayable) : Sayable by say //매개변수로 전달한 객체로 위임 처리
Saying(ps).say()
Saying(pt).say()
//안녕하세요 : 사람
//멍멍멍 : 개
상속관계 클래스 위임 처리 가능
class Screen(val showable: Showable): Showable by showable
val view = View() //View는 Showable 인터페이스를 상속받는 클래스
val customView = CustomView() //CustomView는 View를 상속받는 클래스
Screen(view).show()
Screen(customView).show()
//View 클래스의 show()
//CustomView 클래스의 show()
계층구조를 가져도 위탁자 클래스와 동일한 인터페이스 구현이 되면 이 인터페이스를 기준으로 위임관계를 구성할 수 있다.
여러 인터페이스로 클래스 위임 처리
class Screen(val showable: Showable, val viewable: Viewable): Showable by showable, Viewable by viewable
val show = Show()
val view = View()
Screen(show, view).show() //View.show()
Screen(show, view).view() //CustomView.show()
//Show 클래스의 show()
//View 클래스의 view()
속성 위임
- 클래스 위임에도 by 예약어를 사용했듯이 속성에도 by로 위임을 처리할 수 있다.
- 보통 코틀린 내부적으로 위임을 처리할 수 있는 notNull, vetoable, observable 메서드를 제공한다. 또한, 지연처리를 하는 lazy 함수도 사용할 수 있다.
- 속성에 대한 위임은 속성을 사용할 때 특정한 값을 세팅해서 처리하는 것이다. 이때 Delefates 객체의 notNull, observable, vetoable를 사용한다.
notNull 위임처리
- 속성의 지연초기화는 lateinit 예약어로 처리할 수 있다. 이 방식에서 정수와 실수 프리미티브가 사용되는 자료형은 지연초기화를 할 수 없다.
- 속성 위임을 by로 사용하고 Delegates.notNull 메서드를 사용하면 프리미티브도 위임을 통한 지연초기화가 가능하다.
- Delegates.notNull은 val 속성으로 지정할 때는 사용할 수 없다.
import kotlin.properties.Delegates //코틀린 속성 지연 처리 object
lateinit var str : String //최상위 속성 지연 초기화는 참조 객체만 가능
//lateinit var int : Int //최상위 속성 지연 초기화할 때는 기본 자료형은 불가
var str1 : String by Delegates.notNull<String>()
var int1 : Int by Delegates.notNull<Int>()
//val str2: String by Delegates.notNull<String>() //val은 재할당 금지라서 지연초기화 사용 못함
//val int2: Int by Delegates.notNull<Int>() //val은 재할당 금지라서 지연초기화 사용 못함
str = "초기화 처리"
str1 = "초기화 처리"
int1 = 100
println("lateinit 처리 = $str")
println("notnUll String 처리 = $str1")
println("notNull Int. 처리 = $int1")
//lateinit 처리 = 초기화 처리
//notNull String 처리 = 초기화 처리
//notNull Int. 처리 = 100
속성 변경 관찰
import kotlin.properties.Delegates
var observed = false
var max: Int by Delegates.observable(0) {
_, oldValue, newValue ->
println("변경전 : $oldValue 변경후 : $newValue")
observed = true
}
println(max)
println("관찰상태 = ${observed}")
max = 10
println(max)
println("관찰상태 = ${observed}")
//0
//관찰상태 = false
//변경전 : 0 변경후 : 10
//10
//관찰상태 = true
Q. liveData와 비교해서 Delegates.observable를 썼을 때의 이점이 있을까요?
특정 조건이 일치할 때만 속성 위임 변경
- 속성 위임을 vetoable 메서드로 처리할 경우는 조건이 만족할 때만 속성값을 변경한다.
- 이 속성의 필드를 바꾸면 실제 짝수일 경우에만 값이 변경된다.
var vetoableField: Int by Delegates.vetoable(0) { //변경 거부 여부
_, old, new -> //속성 변경 전
println("변경전 : $old, 변경후 : $new") //변경 상태 확인
new % 2 == 0 //조건이 참인 경우: 짝수 값일 경우만 갱신
}
속성과 지역변수 지연초기화
- 속성 위임을 사용하는 지연처리는 val 속성과 val 변수에서 가능하다.
- 함수 내의 지역변수도 var는 lateinit, val은 by lazy로 지연초기화 처리를 할 수 있다.
Q. 맵 자료형을 사용한 속성 위임 처리는 이점, 활용 목적이 무엇인가요?
'Kotlin > 스터디' 카테고리의 다른 글
코틀린 스터디 - 10장 (0) | 2023.09.17 |
---|---|
코틀린 스터디 - 9장 (1) | 2023.09.10 |
코틀린 스터티 - 8장 (0) | 2023.09.03 |
코틀린 스터디 - 6장 (0) | 2023.08.20 |
코틀린 스터디 - 5장 (0) | 2023.08.13 |