Istnieją pewne typowe rodzaje właściwości, które chociaż możemy zaimplementować je ręcznie za każdym razem, gdy ich potrzebujemy, byłoby bardzo fajnie zaimplementować je raz na zawsze i umieścić w bibliotece. Przykłady obejmują leniwe właściwości: wartość jest obliczana tylko przy pierwszym dostępie, obserwowalne właściwości: słuchacze są powiadamiani o zmianach tej właściwości, przechowując właściwości na mapie, a nie w osobnych polach.
Tutaj delegujesz metodę pobierającą / ustawiającą do innej klasy, która wykonuje pracę i może zawierać wspólny kod. Jako kolejny przykład, niektóre wtryskiwacze zależności dla Kotlin obsługują ten model, delegując metodę pobierającą do otrzymywania wartości z rejestru instancji zarządzanych przez silnik iniekcji zależności.
Wzorzec delegowania okazał się dobrą alternatywą dla dziedziczenia implementacji, a Kotlin obsługuje go natywnie, wymagając zerowego kodu standardowego. Klasa Derived może dziedziczyć z interfejsu Base i delegować wszystkie swoje metody publiczne do określonego obiektu
Tutaj możesz delegować interfejs do innej implementacji, więc klasa implementująca musi tylko przesłonić to, co chce zmienić, podczas gdy pozostałe metody delegują z powrotem do pełniejszej implementacji.
Przykładem na żywo byłyby kolekcje Klutter Readonly / Immutable, w których po prostu delegują określony interfejs kolekcji do innej klasy, a następnie zastępują wszystko, co musi być inne w implementacji tylko do odczytu. Oszczędność pracy bez konieczności ręcznego delegowania wszystkich pozostałych metod.
Krótko mówiąc, możesz zrozumieć bysłowo kluczowe dostarczone przez .
Z punktu widzenia konsumenta własności valjest to coś, co ma getter (get) i varjest czymś, co ma getter i setter (get, set). Dla każdegovar właściwości istnieje domyślny dostawca metod pobierania i ustawiania, których nie musimy jawnie określać.
Ale używając bysłowa kluczowego, stwierdzasz, że ten getter / getter & setter jest udostępniony gdzie indziej (tj. Został delegowany). Jest dostarczana przez funkcję, która jest później by.
Więc zamiast używać tej wbudowanej metody get and set, delegujesz to zadanie do jakiejś jawnej funkcji.
Bardzo częstym przykładem jest by lazyleniwe ładowanie właściwości. Ponadto, jeśli używasz biblioteki iniekcji zależności, takiej jak Koin, zobaczysz wiele właściwości zdefiniowanych w następujący sposób:
var myRepository: MyRepository by inject() //inject is a function from Koin
W definicji klasy kieruje się tą samą zasadą, definiuje, gdzie jest dostarczana jakaś funkcja, ale może odnosić się do dowolnego zestawu metod / właściwości, a nie tylko do pobierania i ustawiania.
classMyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Ten kod mówi: „Jestem klasą MyClass i oferuję funkcje interfejsu SomeInterface, które są dostarczane przez SomeImplementation. Sam zaimplementuję SomeOtherInterface (to niejawne, więc nie byma). '
jeśli spróbujemy uzyskać dostęp do wartości właściwości p , innymi słowy, jeśli wywołamy metodę get () właściwości p , metodę getValue () metody Delegate wywoływana jest instancji .
Jeśli spróbujemy ustawić wartość właściwości p , innymi słowy, jeśli wywołamy metodę set () właściwości p , wywoływana jest metoda setValue () instancji Delegate .
import kotlin.reflect.KProperty
classDelegate{
// for get() method, ref - a reference to the object from // which property is read. prop - propertyoperatorfungetValue(ref: Any?, prop: KProperty<*>) = "textA"// for set() method, 'v' stores the assigned valueoperatorfunsetValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property@JvmStaticfunmain(args: Array<String>) {
println(s)
s = "textB"
}
}
Wynik:
textA
value = textB
Delegacja na zajęcia:
interfaceBaseInterface{
val value: String
funf()
}
classClassA: BaseInterface {overrideval value = "property from ClassA"overridefunf() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public // members from the ClassA.classClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
@JvmStaticfunmain(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
Wynik:
property from ClassA
fun from ClassA
Delegacja parametrów:
// for val properties Map is used; for var MutableMap is usedclassUser(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Intby mapA
var address: String by mapB
var id: Longby mapB
}
object SampleBy {
@JvmStaticfunmain(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}")
}
}
Wynik:
name: John; age: 30; address: city, street; id: 5000
Odpowiedzi:
W referencji Kotlin znajdziesz dwa zastosowania
by
, z których pierwszym są właściwości delegowane, które są zastosowane powyżej:Tutaj delegujesz metodę pobierającą / ustawiającą do innej klasy, która wykonuje pracę i może zawierać wspólny kod. Jako kolejny przykład, niektóre wtryskiwacze zależności dla Kotlin obsługują ten model, delegując metodę pobierającą do otrzymywania wartości z rejestru instancji zarządzanych przez silnik iniekcji zależności.
I Interfejs / klasa delegacja jest inne zastosowanie:
Tutaj możesz delegować interfejs do innej implementacji, więc klasa implementująca musi tylko przesłonić to, co chce zmienić, podczas gdy pozostałe metody delegują z powrotem do pełniejszej implementacji.
Przykładem na żywo byłyby kolekcje Klutter Readonly / Immutable, w których po prostu delegują określony interfejs kolekcji do innej klasy, a następnie zastępują wszystko, co musi być inne w implementacji tylko do odczytu. Oszczędność pracy bez konieczności ręcznego delegowania wszystkich pozostałych metod.
Oba są objęte odniesieniem do języka Kotlin , zacznij tam od podstawowych tematów języka.
źródło
Krótko mówiąc, możesz zrozumieć
by
słowo kluczowe dostarczone przez .Z punktu widzenia konsumenta własności
val
jest to coś, co ma getter (get) ivar
jest czymś, co ma getter i setter (get, set). Dla każdegovar
właściwości istnieje domyślny dostawca metod pobierania i ustawiania, których nie musimy jawnie określać.Ale używając
by
słowa kluczowego, stwierdzasz, że ten getter / getter & setter jest udostępniony gdzie indziej (tj. Został delegowany). Jest dostarczana przez funkcję, która jest późniejby
.Więc zamiast używać tej wbudowanej metody get and set, delegujesz to zadanie do jakiejś jawnej funkcji.
Bardzo częstym przykładem jest
by lazy
leniwe ładowanie właściwości. Ponadto, jeśli używasz biblioteki iniekcji zależności, takiej jak Koin, zobaczysz wiele właściwości zdefiniowanych w następujący sposób:var myRepository: MyRepository by inject() //inject is a function from Koin
W definicji klasy kieruje się tą samą zasadą, definiuje, gdzie jest dostarczana jakaś funkcja, ale może odnosić się do dowolnego zestawu metod / właściwości, a nie tylko do pobierania i ustawiania.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Ten kod mówi: „Jestem klasą MyClass i oferuję funkcje interfejsu SomeInterface, które są dostarczane przez SomeImplementation. Sam zaimplementuję SomeOtherInterface (to niejawne, więc nie
by
ma). 'źródło
Składnia jest następująca:
val/var <property name>: <Type> by <expression>.
Wyrażenie po by to delegat
jeśli spróbujemy uzyskać dostęp do wartości właściwości p , innymi słowy, jeśli wywołamy metodę get () właściwości p , metodę getValue () metody Delegate wywoływana jest instancji .
Jeśli spróbujemy ustawić wartość właściwości p , innymi słowy, jeśli wywołamy metodę set () właściwości p , wywoływana jest metoda setValue () instancji Delegate .
źródło
Delegacja do mienia:
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" } }
Wynik:
Delegacja na zajęcia:
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() } }
Wynik:
property from ClassA fun from ClassA
Delegacja parametrów:
// 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}") } }
Wynik:
name: John; age: 30; address: city, street; id: 5000
źródło