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行编译不过

原文地址:https://www.cnblogs.com/mhbs/p/11509551.html