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

  1. 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
  2. Observable attributes; Property changes can be observed, notified of any changes, and the logical implementation of these observations is delegated to another class
  3. 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