• Kotlin 委托(1)类委托、变量委托注意事项


    1.官方文档

    英文:

      https://kotlinlang.org/docs/reference/delegation.html

      https://kotlinlang.org/docs/reference/delegated-properties.html

    中文:

      https://www.kotlincn.net/docs/reference/delegation.html        

      https://www.kotlincn.net/docs/reference/delegated-properties.html     

    2.委托作用

      用来实现代理/委托模式,可以在不修改原来代码及软件结构的情况下,对原有功能扩展或者修改。也可以在设计时直接使用委托模式方便扩展。

    3.类委托

    3.1 示例

     1 interface __base1__         { fun f2()    }
     2 
     3 class base1Impl : __base1__ {
     4     override fun f2() {
     5         Log.e(TAG_DELEGATE,"base1Impl.f2()")
     6     }
     7 }
     8 
     9 class delegate1(var impl : __base1__) : __base1__ by impl
    10 
    11 
    12 fun delegate_test1(){
    13 
    14     Log.e(TAG_DELEGATE,"====================================== delegate_test_ 1 ")
    15 
    16     var impl = base1Impl()
    17     var delegate1 = delegate1(impl)
    18 
    19     delegate1.f2()
    20 
    21     var d2 = delegate1(object : __base1__{
    22         override fun f2() {
    23             Log.e(TAG_DELEGATE,"delegate1.companion.impl.f2()")
    24         }
    25     })
    26 
    27     d2.f2()
    28 }

      结果

    2019-09-13 09:46:04.165 25360-25360/com.example.kotlin E/delegate: ====================================== delegate_test_ 1 
    2019-09-13 09:46:04.166 25360-25360/com.example.kotlin E/delegate: base1Impl.f2()
    2019-09-13 09:46:04.166 25360-25360/com.example.kotlin E/delegate: delegate1.companion.impl.f2()

      其中:

    • __base1__是接口,
    • base1Impl 是__base1__的实现
    • delegate1  是个委托,它在声明实现接口__base1__,但是并没有实现任何函数。是把它交给它的一个成员impl处理。这个impl就是base1Impl
    • kotlin中使用关键字 by 声明委托。如下:
      class delegate1(var impl : __base1__) : __base1__ by impl

    3.2 接口能被委托,类不可以

    1 open class deleagte_base2
    2 open class delegate_sub1 : deleagte_base2()
    3 class delegate1(base1 : deleagte_base2) : deleagte_base2 by base1   //error 只有接口能被委托,类不可以
    4 
    5 abstract class AB1{
    6     abstract fun f1()
    7 }
    8 class D2 (var ab : AB1) : AB1 by ab         //error,抽象类也不可以委托。

      结果: 第3、8 行编译不过。

    3.3 不要重写委托接口的方法

      不要重写委托接口的方法,否则调用的是重写版本的,不是委托对象的。

     1 interface __I3__ {  fun f3() }
     2 
     3 class I3Impl : __I3__{
     4     override fun f3() {
     5         Log.e(TAG_DELEGATE,"I3Impl.f3()")
     6     }
     7 }
     8 
     9 class delegate3(i3 : __I3__) : __I3__ by i3 {
    10     override fun f3() { //不要重写委托类的方法,否则调用的是重写的,不是委托的。
    11         Log.e(TAG_DELEGATE,"delegate3.f3()")
    12     }
    13 }
    14 
    15 fun delegate_test3(){
    16 
    17     Log.e(TAG_DELEGATE,"====================================== delegate_test_ 3 ")
    18 
    19     var im3 = I3Impl()
    20 
    21     var delegate3 = delegate3(im3)
    22 
    23     delegate3.f3()
    24 
    25 }

      结果

    2019-09-13 10:55:35.772 27606-27606/com.example.kotlin E/delegate: ====================================== delegate_test_ 3 
    2019-09-13 10:55:35.772 27606-27606/com.example.kotlin E/delegate: delegate3.f3()

      delegate3 中的f3被执行,并不是 I3Impl 的f3 被执行。

    4.变量委托

       成员变量全局变量局部变量 的管理都可以委托给其它特定对象。

    4.1 kotlin语言包里自带的变量委托

    委托 作用

    lazy

    不可变量(val)的延迟初始化

    observable

    观察变量的变化
    vetoable 观察变量的变化,且在改值时有否定权
    notNull 变量是否为空,为空是不可使用。
    map 变量委托给一个map管理

    4.2 自带变量委托示例

     1 //成员变量使用委托属性
     2 class delegate4{
     3 
     4     val name : String by lazy(mode = LazyThreadSafetyMode.NONE){
     5         //mode = LazyThreadSafetyMode.PUBLICATION 表示关闭同步锁,默认开启同步锁的
     6         Log.e(TAG_DELEGATE,"lazy called ")
     7         "lazy"
     8     }
     9 
    10     var value : Int by Delegates.observable(initialValue = 0){
    11         prop,old,new ->
    12         Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new")
    13     }
    14 
    15     var count : Int by Delegates.vetoable(initialValue = 8){
    16             prop,old,new ->
    17         Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new ")
    18         false   //return false 表示不接受修改,本次修改被否决
    19     }
    20 
    21     var str : String by Delegates.notNull()     //在未初始化前使用,IllegalStateException。
    22 
    23 }
    24 
    25 fun delegate_test4(){
    26     Log.e(TAG_DELEGATE,"====================================== delegate_test_ 4 ")
    27 
    28     var d4 = delegate4()
    29 
    30     d4.value = 99
    31 
    32     Log.e(TAG_DELEGATE,"d4.name = ${d4.name}")
    33 
    34     d4.value = 1024
    35 
    36     d4.count = 2046
    37 
    38     d4.count = 328
    39 
    40     Log.e(TAG_DELEGATE,"d4.count = ${d4.count}")
    41 
    42 //    Log.e(TAG_DELEGATE,"d4.str = ${d4.str}")    //error d4.str未初始化。
    43     300
    44 }

      结果

    2019-09-13 15:13:25.209 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_ 4 
    2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 0,new = 99
    2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: lazy called 
    2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: d4.name = lazy
    2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 99,new = 1024
    2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 2046 
    2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 328 
    2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: d4.count = 8

       map 示例

     1 class D9(val map8 : Map<String,Any?>){
     2     val name    : String    by map8
     3     val id      : Int       by map8
     4 
     5     var T = 200
     6     //var age     : Int       by T        //error,Int 并没有提供委托函数。
     7     var age : Int  = T
     8 
     9     var mmap = mutableMapOf<String,Any?>()
    10     var desc : String by mmap
    11 
    12     init{
    13         mmap.put("desc","done")
    14     }
    15 
    16     override fun toString(): String {
    17         return "name = $name,id = $id,desc = $desc,age = $age"
    18     }
    19     fun reset(){
    20         mmap.put("desc","null")
    21         this.age = 0
    22         this::age
    23         ::age
    24     }
    25 }
    26 
    27 fun delegate_test9(){
    28     Log.e(TAG_DELEGATE,"====================================== delegate_test_9 ")
    29     var map = mutableMapOf<String,Any?>(
    30         "name"  to "sia"
    31         ,"age"  to 12
    32         ,"id"   to  3
    33     )
    34 
    35     var d9 = D9(map)
    36 
    37     Log.e(TAG_DELEGATE,"d9 = $d9")
    38 
    39     //d9本身的name和id不可修改,但是它的值来自外部map,当map改变时,它们也改了。
    40     map.put("name","nick")
    41     map.put("id",8)
    42     Log.e(TAG_DELEGATE,"d9 = $d9")
    43 
    44     d9.reset()
    45     Log.e(TAG_DELEGATE,"d9 = $d9")
    46 
    47 }

      结果

    2019-09-13 15:13:25.215 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_9 
    2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = sia,id = 3,desc = done,age = 200
    2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = nick,id = 8,desc = done,age = 200
    2019-09-13 15:13:25.217 8175-8175/com.example.kotlin E/delegate: d9 = name = nick,id = 8,desc = null,age = 0

    5.变量委托的注意事项

    5.1 指定初始值时不能使用委托

     1 fun delegate_test5(){
     2     Log.e(TAG_DELEGATE,"====================================== delegate_test_5 ")
     3 
     4     val noinit1 : Int = 10 by Delegates.notNull()   //error,指定初始值时不能使用委托
     5     var noinit2 : Int by Delegates.notNull()        //ok
     6     noinit2 = 20
     7 
     8     val size  = 64 by lazy {  Log.e(TAG_DELEGATE,"init"); 32 }    //error,size已经初始化。
     9     class d8{
    10         var value = 64 by Delegates.notNull<Int>()                //error,value已经初始化。
    11     }
    12 }

      结果:第 4、8、10 行编译不过

    5.2 类型可以省略

    1 fun delegate_test6(){
    2     Log.e(TAG_DELEGATE,"====================================== delegate_test_6 ")
    3 
    4     val notype1 by lazy { 3 }
    5 
    6     val notype2 by lazy { Log.e(TAG_DELEGATE,"init"); "notype2" }
    7 
    8     Log.e(TAG_DELEGATE,"notype1 = $notype1 , notype2 = $notype2")
    9 }

      结果

    2019-09-13 15:41:07.935 8824-8824/com.example.kotlin E/delegate: ====================================== delegate_test_6 
    2019-09-13 15:41:07.936 8824-8824/com.example.kotlin E/delegate: init
    2019-09-13 15:41:07.936 8824-8824/com.example.kotlin E/delegate: notype1 = 3 , notype2 = notype2

    5.3 不能同时指定多个委托

    1 fun delegate_test7(){
    2     Log.e(TAG_DELEGATE,"====================================== delegate_test_7 ")
    3 
    4     val notype1 by lazy { 3 } ,Delegates.notNull()  //error
    5     val SIZE by lazy {  Log.e(TAG_DELEGATE,"init"); 32 }
    6     Log.e(TAG_DELEGATE,"SIZE = $SIZE,不能同时指定多个委托")
    7 }

      结果: 第4行编译不过

  • 相关阅读:
    【转载】jquery取得iframe元素的方法
    【转载】URL重写相关
    【转载】PHP程序员突破成长瓶颈
    【转载】是什么浪费了我的上网时间
    信息化时代下的我们弄潮儿
    如何减小与“大牛”的差距
    servlet应用之cookies&session操作
    Servlet简介及工作原理
    深入学习Tomcat自己动手写服务器(附服务器源码)
    servlet过滤器
  • 原文地址:https://www.cnblogs.com/mhbs/p/11509551.html
Copyright © 2020-2023  润新知