Kotlin seven commissioned

Delegate pattern is a fundamental skill in software design patterns. In entrusting mode, there are two objects involved in the processing the same request, subject receiving a request to delegate the request to another object processing.

Kotlin direct support delegation mode, more elegant, simple. Kotlin achieved by keyword commissioned by.


Class delegate

I.e., a delegate class class method defined in the calling object is actually another class of methods to achieve.

The following examples derived class Derived inherits all the methods Interface Base, and a delegate object Base class passed to implement these methods.

// Create Interface 
interface Base {    
    Fun Print () 
} 

// entrusted to accomplish this class interface 
class BaseImpl (Val X: Int): Base { 
    the override Fun Print () {Print (X)} 
} 

// keyword by establishing delegate class 
class the Derived (B: Base): Base B by 

Fun main (args: the Array <String>) { 
    Val BaseImpl B = (10) 
    the Derived (B) .print () // output 10 
}

 Derived in a statement, by clause said it would b stored in the internal object instance of Derived, and the compiler will generate inherits all the methods from the Base interface and forwards the call to b.

 

Property trust

Property commission refers to the value of a property is not a class directly in the class definition, but it is entrusted to a proxy class, in order to achieve unified management of the property class.

Properties delegate syntax:

Val / var <attribute name>: <type> by <expression>    
  • var / val: attribute type (variable / read only)
  • Property name: attribute name
  • Type: The data type of the attribute
  • Expression: the principal-agent class

After the expression is commissioned by keywords, get property () method (and set () method) will be entrusted to this object getValue () and setValue () method. Property trust does not have to implement any interface, but must provide getValue () function (for the var attribute, you also need setValue () function).

Define a class entrusted

Such need to include getValue () method and setValue () method, and the parameters for the object class thisRef be commissioned, to prop delegate object attribute.

kotlin.reflect.KProperty Import 
// definition contains attributes delegate class 
class Example { 
    var P: String by the Delegate () 
} 

// delegate class 
class the Delegate { 
    operator Fun the getValue (thisRef: ?, the Any Property: KProperty <*>) : String { 
        return "$ thisRef, where $ {property.name} commissioned properties" 
    } 

    operator Fun the setValue (thisRef: ?, the Any property: KProperty <*>, value: String) { 
        the println ( "$ a $ {property thisRef .name} property value assigned to $ ") 
    } 
} 
Fun main (args: the Array <String>) { 
    Val E = Example () 
    the println (EP) // access the property, call getValue () function 

    ep =" Runoob "/ / call setValue () function 
    the println (EP) 
}

Standard commission

Kotlin standard library has built a lot of factories delegate methods to achieve properties.

Lazy lazy properties

lazy () is a function that takes a Lambda expression as a parameter, the function returns a Lazy <T> example, instance returned delegate implemented as delay attributes: first call get () performs passed to lazy ( ) of lamda expression and record the results, follow-up call to get (just returned record results).

 

LazyValue Val: {String by the lazy 
    println ( "computed!") 
    "the Hello" 
} 

Fun main (args: the Array <String>) 
{ 
    println (LazyValue) // // first performance is performed twice output expression 
    println ( "-------------") 
    println (LazyValue which) // first performance, performed twice output expression 
}

  

Observable observable properties

It can be used to implement the observer pattern observable.

Delegates.observable () function accepts two arguments: the first is the initialization value, the second value change properties in response to an event (handler).

After the property assignment is executed in response to an event (handler), which has three parameters: the assigned property, the old value and the new value:

 

kotlin.properties.Delegates Import 

class the User { 
    var name: String by Delegates.observable ( "initial value") 
    { 
        prop, Old, New-> 
        the println ( "Old: Old $ -> new new: $ new new") 
    } 
} 

Fun main (args: the Array <String>) 
{ 
    Val = the User User () 

    user.name = "first assignment" // old: initial value -> new: the first assignment 
    user.name = "second assignment" / / old: first assignment -> new: second assigned 
}

operation result:

old: Initial value -> new: the first assignment
old: first assignment -> new: second assignment

The attributes stored in the map

One common use case is stored in the attribute value in a map (map). This often occurs in applications like parsing JSON or do other "dynamic" in the matter. In this case, you can use the map as a delegate instance itself to achieve the delegate property.

class Site(val map:Map<String,Any?>)
{
    val name:String by map
    val url:String by map
}

fun main(args:Array<String>)
{
    val site = Site(mapOf(
        "name" to "zhaosi",
        "url" to "http://www.zhaosi.com"
    ))

    println(site.name)
    println(site.url)
}

 If you use the var attribute, you need to replace the Map MutableMap: 

class Site(val map: MutableMap<String, Any?>) {
    val name: String by map
    val url: String by map
}


fun main(args:Array<String>)
{
    var map:MutableMap<String,Any?> = mutableMapOf(
        "name" to "zhaosi",
        "url" to "www.zhaosi.com"
    )

    val sit = Site(map)

    println(sit.name)
    println(sit.url)

    println("------------")

    map.put("name","liuneng")
    map.put("url","www.liuneng.com")
    println(sit.name)
    println(sit.url)
}

  

Not Null

notNull applies to those cases unable to determine the value of property in the initialization phase.

import kotlin.properties.Delegates

class Foo{
    var notNullBar:String by Delegates.notNull<String>()
}

fun main(args:Array<String>)
{
    var foo = Foo()
    foo.notNullBar = "bar"
    println(foo.notNullBar)
}

 Note that if the property was accessed before the assignment, then an exception is thrown.

 

Local delegate property

You can declare local variables delegate property. For example, you can make a local variable lazy initialization:

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)

    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}

memoizedFoo variables are only counted at first visit. If someCondition fails, then the variable will not compute.  

Entrusted property requirements

For read-only attribute (that is val attribute), its delegate must provide a function called getValue () of. The function accepts the following parameters:

  • thisRef - owner must attribute type (for extended attribute - refers to the type of the extension) is the same or its supertype
  • property - must be of type KProperty <*> or a supertype

This function returns the attribute must be the same type (or subtype).

For a value of the variable (the mutable) property (i.e., property var), except getValue () function, it must also be an additional delegate a function called setValue (), this function accepts the following parameters:

  • property - must be of type KProperty <*> or a supertype
  • new value - must be the same type of property or its super-type.

Translation rules

Behind each delegate achieve attributes, Kotlin compiler will generate an auxiliary property and entrusted to it. For example, for a property prop, generate a hidden attribute prop $ delegate, and the access code is simply entrusted to the additional properties:

C {class 
    var prop: MyDelegate by the Type () 
} 

// This is generated by the compiler corresponding code: 
class C { 
    Private prop Val $ = MyDelegate the delegate () 
    var prop: the Type 
        GET () = $ prop delegate.getValue (the this, the this :: prop) 
        SET (value: the Type) = $ delegate.setValue prop (the this, the this :: prop, value) 
}

  Kotlin compiler parameters provided all the necessary information about the prop: The first instance of this reference argument to the outside of class C and this is KProperty :: prop reflection type object that describes prop itself.

Provide commission

By definition provideDelegate operator can create extended attribute logic implemented delegate object. If by the right side of the object used to provideDelegate defined as a member or extended functions, it will call the function to create properties delegate instance.

One possible use scenarios provideDelegate is when you create a property (and not only in its getter or setter in) to check the consistency of the properties.

For example, if you want to check the attribute name before binding, you can write:

class ResourceLoader<T>(id: ResourceID<T>) {
    operator fun provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): ReadOnlyProperty<MyUI, T> {
        checkProperty(thisRef, prop.name)
        // 创建委托
    }

    private fun checkProperty(thisRef: MyUI, name: String) { …… }
}

fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { …… }

class MyUI {
    val image by bindResource(ResourceID.image_id)
    val text by bindResource(ResourceID.text_id)
}

  

ProvideDelegate same parameters and getValue:

  • thisRef - owner must attribute type (for extended attribute - refers to the type of the extension) is the same or its supertype
  • property - must be of type KProperty <*> or a supertype.

During the creation of MyUI instance, call provideDelegate method for each property, and perform the necessary verification immediately.

The ability of the binding between the absence of such interception with the entrusted property, in order to achieve the same functionality, you must explicitly pass the property name, which is not very convenient:

// Check attribute name without using "provideDelegate" function 
class MyUI { 
    Val Image by bindResource (ResourceID.image_id, "Image") 
    Val text by bindResource (ResourceID.text_id, "text") 
} 

Fun <T> MyUI.bindResource ( 
        ID: the ResourceID <T>, 
        propertyName: String 
): ReadOnlyProperty <MyUI, T> { 
   , checkProperty (the this, propertyName) 
   // create a delegate 
}

In the generated code, it will call provideDelegate method to initialize auxiliary prop $ delegate property. For comparison property declarations val prop: Type by MyDelegate () code generated in the above (method does not exist when provideDelegate) the generated code:  

C {class 
    var prop: MyDelegate by the Type () 
} 

// This code when "provideDelegate" function is available 
// code generated by the compiler: 
class C { 
    // call "provideDelegate" to create an additional "delegate" properties 
    Private prop Val $ = MyDelegate the delegate () provideDelegate (the this, the this :: prop). 
    Val prop: the Type 
        GET () = $ delegate.getValue prop (the this, the this :: prop) 
}

Please note, provideDelegate create a secondary method only affects the property, and will not affect the generation of the code for the getter or setter.  












Guess you like

Origin www.cnblogs.com/qiangge-python/p/11333034.html