Hay ciertos tipos comunes de propiedades que, aunque podemos implementarlas manualmente cada vez que las necesitemos, sería muy bueno implementarlas de una vez por todas y ponerlas en una biblioteca. Los ejemplos incluyen propiedades diferidas: el valor se calcula solo en el primer acceso, propiedades observables: los oyentes reciben notificaciones sobre los cambios en esta propiedad, almacenando propiedades en un mapa, no en un campo separado cada una.
Aquí delegas el getter / setter a otra clase que hace el trabajo y puede contener código común. Como otro ejemplo, algunos de los inyectores de dependencia para Kotlin admiten este modelo al delegar el captador para recibir un valor de un registro de instancias administrado por el motor de inyección de dependencia.
El patrón de delegación ha demostrado ser una buena alternativa a la herencia de implementación, y Kotlin lo admite de forma nativa y no requiere código repetitivo. Una clase Derived puede heredar de una interfaz Base y delegar todos sus métodos públicos a un objeto específico
Aquí puede delegar una interfaz a otra implementación, por lo que la clase de implementación solo necesita anular lo que quiere cambiar, mientras que el resto de los métodos delegan nuevamente a una implementación más completa.
Un ejemplo vivo serían las colecciones de Klutter Readonly / Immutable donde realmente solo delegan la interfaz de colección específica a otra clase y luego anulan cualquier cosa que deba ser diferente en la implementación de solo lectura. Ahorro de mucho trabajo al no tener que delegar manualmente todos los demás métodos.
En palabras simples, puede comprender la bypalabra clave proporcionada por .
Desde la perspectiva del consumidor de propiedades, vales algo que tiene getter (get) y vares algo que tiene getter y setter (get, set). Para cada varpropiedad hay un proveedor predeterminado de métodos get y set que no necesitamos especificar explícitamente.
Pero, al usar una bypalabra clave, está indicando que este getter / getter & setter se proporciona en otro lugar (es decir, se ha delegado). Está provisto por la función que viene después by.
Entonces, en lugar de usar estos métodos incorporados de obtención y configuración, está delegando ese trabajo a alguna función explícita.
Un ejemplo muy común es el by lazyde las propiedades de carga diferida. Además, si está utilizando una biblioteca de inyección de dependencias como Koin, verá muchas propiedades definidas así:
var myRepository: MyRepository by inject() //inject is a function from Koin
En la definición de clase, sigue el mismo principio, define dónde se proporciona alguna función, pero puede referirse a cualquier conjunto de métodos / propiedades, no solo a obtener y establecer.
classMyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Este código dice: 'Soy clase MyClass y ofrezco funciones de interfaz SomeInterface que son proporcionadas por SomeImplementation. Implementaré SomeOtherInterface por mí mismo (eso está implícito, así que no by) '.
si intentamos acceder al valor de la propiedad p , en otras palabras, si llamamos al método get () de la propiedad p , se invoca el método getValue () de la instancia Delegate .
Si intentamos establecer el valor de la propiedad p , en otras palabras, si llamamos al método set () de la propiedad p , se invoca el método setValue () de la instancia 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"
}
}
Resultado:
textA
value = textB
Delegación de clase:
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()
}
}
Resultado:
property from ClassA
fun from ClassA
Delegación de parámetros:
// 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}")
}
}
Resultado:
name: John; age: 30; address: city, street; id: 5000
Respuestas:
En la referencia de Kotlin encontrará dos usos
by
, el primero es Propiedades delegadas, que es el uso que tiene anteriormente:Aquí delegas el getter / setter a otra clase que hace el trabajo y puede contener código común. Como otro ejemplo, algunos de los inyectores de dependencia para Kotlin admiten este modelo al delegar el captador para recibir un valor de un registro de instancias administrado por el motor de inyección de dependencia.
Y la delegación de interfaz / clase es el otro uso:
Aquí puede delegar una interfaz a otra implementación, por lo que la clase de implementación solo necesita anular lo que quiere cambiar, mientras que el resto de los métodos delegan nuevamente a una implementación más completa.
Un ejemplo vivo serían las colecciones de Klutter Readonly / Immutable donde realmente solo delegan la interfaz de colección específica a otra clase y luego anulan cualquier cosa que deba ser diferente en la implementación de solo lectura. Ahorro de mucho trabajo al no tener que delegar manualmente todos los demás métodos.
Ambos están cubiertos por la referencia del idioma Kotlin , comience allí para los temas básicos del idioma.
fuente
En palabras simples, puede comprender la
by
palabra clave proporcionada por .Desde la perspectiva del consumidor de propiedades,
val
es algo que tiene getter (get) yvar
es algo que tiene getter y setter (get, set). Para cadavar
propiedad hay un proveedor predeterminado de métodos get y set que no necesitamos especificar explícitamente.Pero, al usar una
by
palabra clave, está indicando que este getter / getter & setter se proporciona en otro lugar (es decir, se ha delegado). Está provisto por la función que viene despuésby
.Entonces, en lugar de usar estos métodos incorporados de obtención y configuración, está delegando ese trabajo a alguna función explícita.
Un ejemplo muy común es el
by lazy
de las propiedades de carga diferida. Además, si está utilizando una biblioteca de inyección de dependencias como Koin, verá muchas propiedades definidas así:var myRepository: MyRepository by inject() //inject is a function from Koin
En la definición de clase, sigue el mismo principio, define dónde se proporciona alguna función, pero puede referirse a cualquier conjunto de métodos / propiedades, no solo a obtener y establecer.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Este código dice: 'Soy clase MyClass y ofrezco funciones de interfaz SomeInterface que son proporcionadas por SomeImplementation. Implementaré SomeOtherInterface por mí mismo (eso está implícito, así que no
by
) '.fuente
La sintaxis es:
val/var <property name>: <Type> by <expression>.
La expresión después de es el delegado
si intentamos acceder al valor de la propiedad p , en otras palabras, si llamamos al método get () de la propiedad p , se invoca el método getValue () de la instancia Delegate .
Si intentamos establecer el valor de la propiedad p , en otras palabras, si llamamos al método set () de la propiedad p , se invoca el método setValue () de la instancia Delegate .
fuente
Delegación de propiedad:
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" } }
Resultado:
Delegación de clase:
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() } }
Resultado:
property from ClassA fun from ClassA
Delegación de parámetros:
// 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}") } }
Resultado:
name: John; age: 30; address: city, street; id: 5000
fuente