Существуют определенные общие типы свойств, которые, хотя мы можем реализовать их вручную каждый раз, когда они нам нужны, было бы очень хорошо реализовать раз и навсегда и поместить в библиотеку. Примеры включают ленивые свойства: значение вычисляется только при первом доступе, наблюдаемые свойства: слушатели получают уведомления об изменениях этого свойства, сохраняя свойства на карте, а не в каждом отдельном поле.
Здесь вы делегируете геттер / сеттер другому классу, который выполняет эту работу и может содержать общий код. В качестве другого примера, некоторые из инжекторов зависимостей для Kotlin поддерживают эту модель, делегируя геттеру получение значения из реестра экземпляров, управляемых механизмом внедрения зависимостей.
Шаблон делегирования оказался хорошей альтернативой наследованию реализации, и Kotlin поддерживает его, изначально не требуя шаблонного кода. Класс Derived может наследовать от интерфейса Base и делегировать все свои общедоступные методы указанному объекту.
Здесь вы можете делегировать интерфейс другой реализации, поэтому классу реализации нужно только переопределить то, что он хочет изменить, в то время как остальные методы делегируются обратно более полной реализации.
Живым примером могут быть коллекции Klutter Readonly / Immutable, где они действительно просто делегируют конкретный интерфейс коллекции другому классу, а затем переопределяют все, что должно отличаться в реализации только для чтения. Экономия большого объема работы без необходимости вручную делегировать все другие методы.
Обе они описаны в справочнике по языку Kotlin , начиная с него, чтобы познакомиться с базовыми темами языка.
Проще говоря, вы можете понять byключевое слово как предоставленное .
С точки зрения потребителя свойства, valэто то, что имеет геттер (get) и varто, что имеет геттер и сеттер (get, set). Для каждого varсвойства есть поставщик по умолчанию для методов get и set, который нам не нужно указывать явно.
Но, используя byключевое слово, вы утверждаете, что этот метод получения / получения и установки предоставляется где-то еще (т.е. он был делегирован). Это обеспечивается с помощью функции , которая приходит после by.
Таким образом, вместо использования этих встроенных методов get и set вы делегируете эту работу какой-то явной функции.
Один очень распространенный пример - by lazyсвойства отложенной загрузки. Кроме того, если вы используете библиотеку внедрения зависимостей, такую как Koin, вы увидите множество свойств, определенных следующим образом:
var myRepository: MyRepository by inject() //inject is a function from Koin
В определении класса он следует тому же принципу, он определяет, где предоставляется какая-либо функция, но может относиться к любому набору методов / свойств, а не только к получению и установке.
classMyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Этот код говорит: «Я класс MyClass, и я предлагаю функции интерфейса SomeInterface, которые предоставляются SomeImplementation. Я сам буду реализовывать SomeOtherInterface (это неявно, так что нет by) ».
если попытаться получить доступ к значению свойств р , иными словами, если мы называем получить () метод свойств р , то ПолучитьЗначение () метод делегата экземпляра .
Если мы попытаемся установить значение свойства p , другими словами, если мы вызовем метод set () свойства p , будет вызван метод setValue () экземпляра 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"
}
}
Результат:
textA
value = textB
Делегация на занятие:
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()
}
}
Результат:
property from ClassA
fun from ClassA
Делегирование параметров:
// 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}")
}
}
Результат:
name: John; age: 30; address: city, street; id: 5000
Ответы:
В справочнике Kotlin вы найдете два использования
by
, первое из которых - это делегированные свойства, которые вы использовали выше:Здесь вы делегируете геттер / сеттер другому классу, который выполняет эту работу и может содержать общий код. В качестве другого примера, некоторые из инжекторов зависимостей для Kotlin поддерживают эту модель, делегируя геттеру получение значения из реестра экземпляров, управляемых механизмом внедрения зависимостей.
И делегирование интерфейса / класса - другое использование:
Здесь вы можете делегировать интерфейс другой реализации, поэтому классу реализации нужно только переопределить то, что он хочет изменить, в то время как остальные методы делегируются обратно более полной реализации.
Живым примером могут быть коллекции Klutter Readonly / Immutable, где они действительно просто делегируют конкретный интерфейс коллекции другому классу, а затем переопределяют все, что должно отличаться в реализации только для чтения. Экономия большого объема работы без необходимости вручную делегировать все другие методы.
Обе они описаны в справочнике по языку Kotlin , начиная с него, чтобы познакомиться с базовыми темами языка.
источник
Проще говоря, вы можете понять
by
ключевое слово как предоставленное .С точки зрения потребителя свойства,
val
это то, что имеет геттер (get) иvar
то, что имеет геттер и сеттер (get, set). Для каждогоvar
свойства есть поставщик по умолчанию для методов get и set, который нам не нужно указывать явно.Но, используя
by
ключевое слово, вы утверждаете, что этот метод получения / получения и установки предоставляется где-то еще (т.е. он был делегирован). Это обеспечивается с помощью функции , которая приходит послеby
.Таким образом, вместо использования этих встроенных методов get и set вы делегируете эту работу какой-то явной функции.
Один очень распространенный пример -
by lazy
свойства отложенной загрузки. Кроме того, если вы используете библиотеку внедрения зависимостей, такую как Koin, вы увидите множество свойств, определенных следующим образом:var myRepository: MyRepository by inject() //inject is a function from Koin
В определении класса он следует тому же принципу, он определяет, где предоставляется какая-либо функция, но может относиться к любому набору методов / свойств, а не только к получению и установке.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Этот код говорит: «Я класс MyClass, и я предлагаю функции интерфейса SomeInterface, которые предоставляются SomeImplementation. Я сам буду реализовывать SomeOtherInterface (это неявно, так что нет
by
) ».источник
Синтаксис:
val/var <property name>: <Type> by <expression>.
Выражение после by является делегатом
если попытаться получить доступ к значению свойств р , иными словами, если мы называем получить () метод свойств р , то ПолучитьЗначение () метод делегата экземпляра .
Если мы попытаемся установить значение свойства p , другими словами, если мы вызовем метод set () свойства p , будет вызван метод setValue () экземпляра Delegate .
источник
Делегирование на имущество:
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" } }
Результат:
Делегация на занятие:
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
источник