What is a delegate?
Entrust your affairs to others.
A common proxy pattern is that the proxied class receives a delegate from the proxy class to handle the affairs of the proxy class.
I won’t talk about design patterns here, just class and attribute delegates from Kotlin.
Class delegate: Delegate your own business to another class
Why do WE need delegates?
A property delegate can replace the getter and setter for the current property with a property of another class.
Class delegates can use composition instead of inheritance.
Kotlin supports delegates at the syntactic level, reducing boilerplate code
In what context?
Attribute to entrust
This is used when you want to put the reading logic of a property in another place, for example, if you want to change the name of a property, and the library has already been sent out, there is no way to delete it, only to discard it, you can use a delegate to delegate the old property to the new property.
There are also several scenarios available in the standard library
- Delayed initialization; Properties are initialized the first time they are used, and the delay logic is left outside the class and delegated to another class
- Observable attributes; Property changes can be observed, notified of any changes, and the logical implementation of these observations is delegated to another class
- Store multiple attributes in a map instead of each in a separate field.
Commissioned by class
The delegate pattern has proven to be a good alternative to implementing inheritance.
How to use it?
Kotlin supports delegation at the syntactic level, and the compiler will help us generate boilerplate code.
Entrusted property
Grammar:
Val /var < attribute name >: < type > by < expression > The expression after BY is the delegate.Copy the code
class Example {
var p: String by Delegate()
}
Copy the code
Properties in the library defer initialization and observable delegate usage
val s:String by lazy {
"Hello s."
}
val name :String by Delegates.observable("Buddha code"){property,oldValue,newValue ->
println("${property.name}The value of is about to change, new value:${newValue}, the old value:${newValue}")}Copy the code
The library’s factory method lazy, which provides a lazy attribute delegate, is used by a lambda that passes in an initialized value.
It will only be called once if the lambda has not been assigned and will store the return value of the lambda. After a successful assignment, the value will be used directly without calling the lambda expression again. If an assignment error occurs, it will be called again until the assignment succeeds.
Lazy also takes an optional mode,
val s:String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
"Hello s."
}
Copy the code
This parameter takes an enumeration type, LazyThreadSafetyMode, which currently has three enumeration values
- LazyThreadSafetyMode. SYNCHRONIZED lock and make sure there is only one thread can initialize Lazy instance; The default value.
- LazyThreadSafetyMode. PUBLICATION initialization function can be called many times, but only the return value is used for the first time.
- No lock LazyThreadSafetyMode. NONE
In addition to lazy Delegates, there are many Delegates in the Delegates class in the standard library, not to mention the Delegates in the source code or Kotlin Programming Practices Chapter 8.
Commissioned by class
interface Base {
fun print(a)
}
class BaseImpl(val x: Int) : Base {
override fun print(a) { print(x) }
}
class Derived(b: Base) : Base by b
fun main(a) {
val b = BaseImpl(10)
Derived(b).print()
}
Copy the code
How do I customize property delegates
The delegate class only needs to provide getValue and setValue (corresponding to the var variable) functions, without implementing any interface.
The standard function signature is as follows
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any? , property:KProperty< * >): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any? , property:KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")}}Copy the code
ReadOnlyProperty and ReadWriteProperty correspond to val and var, respectively.
The sample
class Example{
var p :String by MyDelegate()
val s:String by lazy {
"Hello s."}}class MyDelegate:ReadWriteProperty<Example,String>{
override fun setValue(thisRef: Example, property: KProperty<*>, value: String) {
println("MyDelegate setValue is called thisRef:$thisRef , property:${property.name} , value:$value")}override fun getValue(thisRef: Example, property: KProperty< * >): String {
return "MyDelegate getValue is called thisRef:$thisRef,property:${property.name}"}}Copy the code
How is Kotlin’s delegate implemented?
The delegate in Kotlin is generated by the compiler code, which can be seen when compiled into Java code.
Property delegates delegate getters and setters of the property to the delegate class getValue and setValue. The class delegate is simpler, with the implementation of the delegate called entirely internally.
It’s a little more intuitive to go directly to the code, and compile the above example into Java code to see the following code
The delegate property p only has setter and getter methods. The property itself does not exist in the class member.
Learning materials
- Entrusted property
- Kotlin Programming Practices
- Kotlin Core Programming