Es gibt bestimmte gängige Arten von Eigenschaften, die, obwohl wir sie jedes Mal manuell implementieren können, wenn wir sie benötigen, sehr gut ein für alle Mal implementiert und in eine Bibliothek gestellt werden können. Beispiele hierfür sind verzögerte Eigenschaften: Der Wert wird nur beim ersten Zugriff berechnet. Beobachtbare Eigenschaften: Listener werden über Änderungen an dieser Eigenschaft benachrichtigt, wobei Eigenschaften in einer Karte gespeichert werden und nicht jeweils in einem separaten Feld.
Hier delegieren Sie den Getter / Setter an eine andere Klasse, die die Arbeit erledigt und allgemeinen Code enthalten kann. Als weiteres Beispiel unterstützen einige der Abhängigkeitsinjektoren für Kotlin dieses Modell, indem sie den Getter an den Empfang eines Werts aus einer Registrierung von Instanzen delegieren, die von der Abhängigkeitsinjektions-Engine verwaltet werden.
Das Delegierungsmuster hat sich als gute Alternative zur Implementierungsvererbung erwiesen, und Kotlin unterstützt es nativ, wenn kein Boilerplate-Code erforderlich ist. Eine abgeleitete Klasse kann von einer Schnittstellenbasis erben und alle ihre öffentlichen Methoden an ein angegebenes Objekt delegieren
Hier können Sie eine Schnittstelle an eine andere Implementierung delegieren, sodass die implementierende Klasse nur überschreiben muss, was geändert werden soll, während die übrigen Methoden an eine umfassendere Implementierung zurück delegieren.
Ein Live-Beispiel wären die Klutter Readonly / Immutable-Sammlungen, bei denen sie die spezifische Sammlungsschnittstelle wirklich nur an eine andere Klasse delegieren und dann alles überschreiben, was in der schreibgeschützten Implementierung anders sein muss. Sie sparen viel Arbeit, ohne alle anderen Methoden manuell delegieren zu müssen.
In einfachen Worten können Sie das bySchlüsselwort verstehen, wie es von bereitgestellt wird .
Aus der Sicht des Immobilienkonsumenten valist es etwas, das Getter (get) und varetwas, das Getter und Setter (get, set) hat. Für jede varEigenschaft gibt es einen Standardanbieter für get- und set-Methoden, die wir nicht explizit angeben müssen.
Wenn bySie jedoch ein Schlüsselwort verwenden, geben Sie an, dass dieser Getter / Getter & Setter an anderer Stelle bereitgestellt wird (dh delegiert wurde). Es wird von der Funktion bereitgestellt , die danach kommt by.
Anstatt diese integrierten Methoden zum Abrufen und Festlegen zu verwenden, delegieren Sie diesen Job an eine explizite Funktion.
Ein sehr häufiges Beispiel sind die by lazyEigenschaften für verzögertes Laden. Wenn Sie eine Abhängigkeitsinjektionsbibliothek wie Koin verwenden, werden viele Eigenschaften wie folgt definiert:
var myRepository: MyRepository by inject() //inject is a function from Koin
In der Klassendefinition folgt es dem gleichen Prinzip, es definiert, wo eine Funktion bereitgestellt wird, aber es kann auf jede Reihe von Methoden / Eigenschaften verweisen, nicht nur auf get und set.
classMyClass: SomeInterface by SomeImplementation, SomeOtherInterface
In diesem Code heißt es: 'Ich bin Klasse MyClass und biete Funktionen der Schnittstelle SomeInterface an, die von SomeImplementation bereitgestellt werden. Ich werde SomeOtherInterface selbst implementieren (das ist implizit, also nein byda). '
Wenn wir versuchen, auf den Wert der Eigenschaft p zuzugreifen , dh wenn wir die get () -Methode der Eigenschaft p aufrufen , wird die getValue () -Methode der Delegate- Instanz aufgerufen.
Wenn wir versuchen, den Wert der Eigenschaft p festzulegen , dh wenn wir die set () -Methode der Eigenschaft p aufrufen , wird die setValue () -Methode der Delegate- Instanz aufgerufen.
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"
}
}
Ergebnis:
textA
value = textB
Delegation für die Klasse:
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()
}
}
Ergebnis:
property from ClassA
fun from ClassA
Delegierung für Parameter:
// 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}")
}
}
Ergebnis:
name: John; age: 30; address: city, street; id: 5000
Antworten:
In der Kotlin-Referenz finden Sie zwei Verwendungszwecke für
by
: Die erste sind delegierte Eigenschaften, die oben verwendet werden:Hier delegieren Sie den Getter / Setter an eine andere Klasse, die die Arbeit erledigt und allgemeinen Code enthalten kann. Als weiteres Beispiel unterstützen einige der Abhängigkeitsinjektoren für Kotlin dieses Modell, indem sie den Getter an den Empfang eines Werts aus einer Registrierung von Instanzen delegieren, die von der Abhängigkeitsinjektions-Engine verwaltet werden.
Und die Schnittstellen- / Klassendelegation ist die andere Verwendung:
Hier können Sie eine Schnittstelle an eine andere Implementierung delegieren, sodass die implementierende Klasse nur überschreiben muss, was geändert werden soll, während die übrigen Methoden an eine umfassendere Implementierung zurück delegieren.
Ein Live-Beispiel wären die Klutter Readonly / Immutable-Sammlungen, bei denen sie die spezifische Sammlungsschnittstelle wirklich nur an eine andere Klasse delegieren und dann alles überschreiben, was in der schreibgeschützten Implementierung anders sein muss. Sie sparen viel Arbeit, ohne alle anderen Methoden manuell delegieren zu müssen.
Beide werden in der Kotlin-Sprachreferenz behandelt . Beginnen Sie dort mit den Basisthemen der Sprache.
quelle
In einfachen Worten können Sie das
by
Schlüsselwort verstehen, wie es von bereitgestellt wird .Aus der Sicht des Immobilienkonsumenten
val
ist es etwas, das Getter (get) undvar
etwas, das Getter und Setter (get, set) hat. Für jedevar
Eigenschaft gibt es einen Standardanbieter für get- und set-Methoden, die wir nicht explizit angeben müssen.Wenn
by
Sie jedoch ein Schlüsselwort verwenden, geben Sie an, dass dieser Getter / Getter & Setter an anderer Stelle bereitgestellt wird (dh delegiert wurde). Es wird von der Funktion bereitgestellt , die danach kommtby
.Anstatt diese integrierten Methoden zum Abrufen und Festlegen zu verwenden, delegieren Sie diesen Job an eine explizite Funktion.
Ein sehr häufiges Beispiel sind die
by lazy
Eigenschaften für verzögertes Laden. Wenn Sie eine Abhängigkeitsinjektionsbibliothek wie Koin verwenden, werden viele Eigenschaften wie folgt definiert:var myRepository: MyRepository by inject() //inject is a function from Koin
In der Klassendefinition folgt es dem gleichen Prinzip, es definiert, wo eine Funktion bereitgestellt wird, aber es kann auf jede Reihe von Methoden / Eigenschaften verweisen, nicht nur auf get und set.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
In diesem Code heißt es: 'Ich bin Klasse MyClass und biete Funktionen der Schnittstelle SomeInterface an, die von SomeImplementation bereitgestellt werden. Ich werde SomeOtherInterface selbst implementieren (das ist implizit, also nein
by
da). 'quelle
Die Syntax lautet:
val/var <property name>: <Type> by <expression>.
Der Ausdruck nach by ist der Delegat
Wenn wir versuchen, auf den Wert der Eigenschaft p zuzugreifen , dh wenn wir die get () -Methode der Eigenschaft p aufrufen , wird die getValue () -Methode der Delegate- Instanz aufgerufen.
Wenn wir versuchen, den Wert der Eigenschaft p festzulegen , dh wenn wir die set () -Methode der Eigenschaft p aufrufen , wird die setValue () -Methode der Delegate- Instanz aufgerufen.
quelle
Delegation für Eigentum:
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" } }
Ergebnis:
Delegation für die Klasse:
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() } }
Ergebnis:
property from ClassA fun from ClassA
Delegierung für Parameter:
// 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}") } }
Ergebnis:
name: John; age: 30; address: city, street; id: 5000
quelle