Я перебираю несколько ссылок ( Одна , Две ) и документация относительно шаблона делегата и в некоторой степени понимаю преимущество, которое он приносит в виде « композиция по наследству ». Я вижу, как полезны встроенные свойства делегата (lazy, vetoable, map, observable); но с трудом понимая 2 области:
1. Почему / Когда я должен написать пользовательский делегат для свойства? Как это лучше, чем переопределение getter / setter этого свойства?
Сравнение 2 подходов:
private var withoutDelegate: String = ""
get() = DataHelper.getLatestData(::withoutDelegate.name)
set(value) {
DataHelper.setLatestData(value)
field = value
}
val withDelegate by StringDelegateProvider()
class StringDelegateProvider {
operator fun getValue(thisRef: String?, property: KProperty<*>): String {
return DataHelper.getLatestData(property.name)
}
}
2. На уровне класса, как делегирование лучше, чем традиционные образцы композиции?
Сравнение двух подходов - составление без делегирования кажется гораздо более кратким:
interface Base {
fun print()
}
class BaseImpl1(val x: Int) : Base {
override fun print() { print(x) }
}
class BaseImpl2(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun clientFunctionWithDelegation() {
val i1 = BaseImpl1(10)
val i2 = BaseImpl2(10)
val b1 = Derived(i1)
val b2 = Derived(i2)
b1.print()
b2.print()
}
fun clientFunctionWithoutDelegation(){
//wihtout extending Base, we can still create multiple types of Base and use them conditionally.
val i1: Base = BaseImpl1(10)
val i2: Base = BaseImpl2(10)
i1.print()
i2.print()
}
Буду признателен, если сообщество сможет поделиться некоторыми примерами использования, в которых может помочь делегирование.