Android 용으로 개발하는 동안 때때로 다음과 같은 것을 발견합니다.
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
by
키워드 의 중요성을 이해하지 못합니다 .
답변:
에서 코 틀린 참조 당신은 두 가지 용도를 찾을 수 있습니다 by
, 첫 번째 인 위임 속성 은 위가 사용하는 것입니다 :
특정한 공통된 종류의 속성이 있는데, 우리가 필요할 때마다 수동으로 구현할 수 있지만 한 번에 구현하고 라이브러리에 넣는 것이 매우 좋습니다. 예를 들어 lazy 속성 : 값은 처음 액세스 할 때만 계산 됨, 관찰 가능한 속성 : 리스너는이 속성의 변경 사항에 대해 알림을 받고 속성을 각각 별도의 필드가 아닌 맵에 저장합니다.
여기서 작업을 수행하고 공통 코드를 포함 할 수있는 다른 클래스에 getter / setter를 위임합니다. 또 다른 예로, Kotlin의 일부 종속성 주입기는 종속성 주입 엔진이 관리하는 인스턴스의 레지스트리에서 값을 수신하도록 getter를 위임하여이 모델을 지원합니다.
그리고 인터페이스 / 클래스 위임 은 다른 용도입니다.
위임 패턴은 구현 상속에 대한 좋은 대안으로 입증되었으며 Kotlin은 기본적으로 상용구 코드가 필요하지 않도록 지원합니다. Derived 클래스는 Base 인터페이스에서 상속하고 모든 공용 메서드를 지정된 개체에 위임 할 수 있습니다.
여기에서 인터페이스를 다른 구현에 위임 할 수 있으므로 구현 클래스는 변경하려는 내용 만 재정의하면되고 나머지 메서드는 완전한 구현으로 다시 위임됩니다.
라이브 예제는 Klutter Readonly / Immutable 컬렉션 으로, 특정 컬렉션 인터페이스를 다른 클래스에 위임 한 다음 읽기 전용 구현에서 달라야하는 모든 것을 재정의합니다. 다른 모든 메서드를 수동으로 위임 할 필요없이 많은 작업을 절약 할 수 있습니다.
이 두 가지 모두 Kotlin 언어 참조 에서 다루고 있으며 언어의 기본 주제부터 시작합니다.
간단히 말해서에서 제공하는by
키워드를 이해할 수 있습니다 .
속성 소비자의 관점에서 보면 val
getter (get) var
가 있고 getter와 setter (get, set)가있는 것입니다. 각 var
속성에는 명시 적으로 지정할 필요가없는 get 및 set 메서드의 기본 공급자가 있습니다.
그러나 by
키워드를 사용할 때이 getter / getter & setter가 다른 곳에서 제공된다는 것을 나타냅니다 (즉, 위임 됨). 그것은 것 제공 하여 뒤에 오는 기능 by
.
따라서이 내장 get 및 set 메서드를 사용하는 대신 해당 작업을 명시 적 함수에 위임합니다.
매우 일반적인 예는 by lazy
지연 로딩 속성입니다. 또한 Koin과 같은 종속성 주입 라이브러리를 사용하는 경우 다음과 같이 정의 된 많은 속성을 볼 수 있습니다.
var myRepository: MyRepository by inject() //inject is a function from Koin
클래스 정의에서 동일한 원칙을 따르며 일부 기능이 제공되는 위치를 정의하지만 get 및 set뿐만 아니라 모든 메서드 / 속성 집합을 참조 할 수 있습니다.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
이 코드는 '저는 MyClass 클래스이고 SomeImplementation에서 제공하는 SomeInterface 인터페이스의 기능을 제공합니다. SomeOtherInterface를 직접 구현할 것입니다 (암시 적이므로 by
거기에 없습니다 ). '
재산 위임 :
import kotlin.reflect.KProperty
class Delegate {
// for get() method, ref - a reference to the object from
// which property is read. prop - property
operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
// for set() method, 'v' stores the assigned value
operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property
@JvmStatic fun main(args: Array<String>) {
println(s)
s = "textB"
}
}
결과:
textA
value = textB
수업 위임 :
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
결과:
property from ClassA
fun from ClassA
매개 변수 위임 :
// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Int by mapA
var address: String by mapB
var id: Long by mapB
}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val user = User(mapOf("name" to "John", "age" to 30),
mutableMapOf("address" to "city, street", "id" to 5000L))
println("name: ${user.name}; age: ${user.age}; " +
"address: ${user.address}; id: ${user.id}")
}
}
결과:
name: John; age: 30; address: city, street; id: 5000