[코틀린기초] 28. 위임(delegation)
비유하자면 직원이 사장의 권한을 위임받아 사장의 권한을 행사하는 것
- 하나의 클래스가 다른 클래스에 위임하도록 선언
- 위임된 클래스가 가지는 멤버를 참조없이 호출
<var | val | class> 프로퍼티 혹은 클래스 이름 : 자료형 by 위임자
## 위임을 사용하는 이유?
- 코틀린의 기본 라이브러리는 open되지 않은 최종 클래스
- 표준 라이브러리의 무분별 상속을 방지한다.
-
단, 상속이나 직접 클래스의 확장이 어렵다.
- 위임을 사용하면 상속과 비슷하게 최종 클래스의 모든 기능을 사용하면서, 동시에 기능을 확장할 수 있다.
## 다른 클래스 멤버를 사용하도록 위임
interface Animal{
fun eat(){...}
}
class Car : Animal{}
val cat = Cat()
class Robot : Animal by cat // Animal의 정의된 cat의 모든 멤버를 Robot에 위임
## 예제 코드
interface Car{
fun go(): String
}
class VanImpl(val power: String): Car{
override fun go() = "는 짐을 적재하며 $power 마력을 가집니다."
}
class SportImpl(val power: String): Car{
override fun go() = "는 경주용에 사용되며 $power 마력을 가집니다."
}
class CarModel(val model: String, impl: Car): Car by impl {
fun carInfo(){
println("$model ${go()}") // 참조 없이 각 인터페이스 구현 클래스의 go를 접근
}
}
fun main(){
val myDamas = CarModel("Damas 2010", VanImpl("100마력"))
val my350z = CarModel("350Z 2008", SportImpl("350마력"))
myDamas.carInfo() // carInfo에 대한 다형성을 나타냄
my350z.carInfo()
}
## 프로퍼티 위임과 by lazy
- by lazy {…}도 위임이다.
- 사용된 프로퍼티는 람다식 함수에 전달되어 함수에 의해 사용
#### 동작 분석
- lazy 람다식 함수는 람다를 전달받아 저장한 Lazy
인스턴스를 반환한다. - 최초 프로퍼티의 게터 실행은 lazy에 넘겨진 람다식 함수를 실행하고 결과를 기록한다.
- 이후 프로퍼티의 게터 실행은 이미 초기화되어 기록된 값을 반환한다.
## observable과 vetoable의 위임
-
observable : 프로퍼티를 감시하고 있다가 특정 코드의 로직에서 변경이 일어날 때 호출
-
vetoable : 수여한다는 의미로, 반환값에 따라 프로퍼티 변경을 허용하거나 취소
#### observable 사용 예제
class User{
// observable은 값의 변화를 감시하는 일종의 콜백 루틴
var name: String by Delegates.observable("NONAME"){ // 프로퍼티를 위임, NONAME은 초깃값
prop, old, new -> // 람다식 매개변수로 프로퍼티, 기존 값, 새로운 값
println("$old -> $new") // 이벤트가 발생할 때만 실행됨
}
}
fun main(){
val user = User()
user.name = "Kildong" // 값이 변경되므로 첫 이벤트 발생
user.name = "Dooly" // 값이 변경되므로 두번째 이벤트 발생
}
#### vetoable 사용 예제
fun main(){
var max: Int by Delegates.vetoable(0){
prop, old, new ->
new > old // 조건에 맞지 않으면 거부권 행사
}
println(max) // 0
max = 10
println(max) // 10
max= 5 // 거부됨
println(max) // 10
}