Kotlin for android学习八:委托

前言

kotlin官网kotlin教程学习教程的笔记。

一、类的委托

背景:委托模式是类继承模式之外的另一种很好的替代方案,kotlin直接支持委托模式。
定义:类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。

interface CanFly{
  fun fly()
}
class Bird(f:CanFly):CanFly by f // 只有接口可以委托哦!编译器会生成继承自CanFly接口的所有方法,并将调用转发给f对象

class AnimalWithWings :CanFly{
    override fun fly() {
        println("use wings to fly")
    }
}
class Bat:CanFly  by AnimalWithWings() //编译器会生成继承自CanFly接口的所有方法,并将调用转发给AnimalWithWings对象
fun main(){
    Bird(AnimalWithWings()).fly()
    Bat().fly()
}

二、委托属性

背景:具有共性的属性,在每个需要这些属性的类中手工实现比较麻烦,如果能够只实现一次,供所有需要的类使用,那将会好很多。
定义:一个类的某个属性值不在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理
语法:val/var <属性名>: <类型> by <表达式>
官网上的自定义委托实现方式是这样的,

class User {
    var c: String by C()
}
class C {
    operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        println("$thisRef 的${property.name}属性赋值为$value")
    }
    operator fun getValue(thisRef: Any, property: KProperty<*>): String {
        return "$thisRef,委托了${property.name}属性"
    }
}

更快捷的实现方式如下:

class User {
    var c: String by C()
}
class C : ReadWriteProperty<Any, String> {
    override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        println("${thisRef}的${property.name}属性赋值为$value")
    }
    override fun getValue(thisRef: Any, property: KProperty<*>): String {
        return "$thisRef,委托了${property.name}属性"
    }
}

这里看一下ReadWriteProperty类的内容:

public interface ReadWriteProperty<in R, T> {
    public abstract operator fun getValue(thisRef: R, property: kotlin.reflect.KProperty<*>): T

    public abstract operator fun setValue(thisRef: R, property: kotlin.reflect.KProperty<*>, value: T): kotlin.Unit
}

输出
com.example.demo.User@9bdf2f3的c属性赋值为c
com.example.demo.User@9bdf2f3,委托了c属性

三、标准委托

Kotlin 标准库中提供了一些工厂方法, 可以实现几种很有用的委托
1. 延迟加载

lazy()是一个函数,接受一个lambda表达式作为参数,返回一个Lazy<T>类型的实例,这个实例可以作为一个委托,实现延迟加载属性:第一次调用 get() 时, 将会执行 lazy() 函数受到的 Lambda 表达式, 然后会记住这次执行的结果, 以后所有对 get() 的调用都只会简单地返回以前记住的结果,

  val l by lazy {
        println("computed")
        "lazy"
    }

  var user = User()
   println(user.l) // 输出computed lazy
   println(user.l) //输出lazy

2. 可观察属性

有了这个,再也不用思考怎么实时监控属性变化了\(^o^)/~

  • Delegates.observable()

Delegates.observable() 函数接受两个参数:第一个是初始化值,第二个是属性值变化事件的响应器 (handler). 每次我们向属性赋值时, 响应器(handler)都会被调用(在属性赋值处理完成 之后). 响应器收到三 个参数: 被赋值的属性, 赋值前的旧属性值, 以及赋值后的新属性值

class User {
    var o by Delegates.observable("<none>") {
        kProperty: KProperty<*>, old: String, new: String ->
        println("${kProperty.name}: $old -> $new")
    }
}

 var user = User()
 println(user.o) // 输出<none>
user.o = "first change" // 输出o: <none> -> first change
println(user.o) // first change
 user.o = "second change" // 输出 o: first change -> second change
println(user.o) // 输出second change
  • Delegates.vetoable()

如果你希望能够拦截属性的赋值操作, 并且还能够 “否决” 赋值操作, 那么不要使用 observable() 函数, 而应该改用 vetoable() 函数. 传递给 vetoable 函数的事件响应器, 会在属性赋值处理执行之前被调用.

    var v by Delegates.vetoable("<none>") {
        kProperty: KProperty<*>, old: String, new: String ->
        println("${kProperty.name}: $old -> $new")
        new.contains("change")
    }

      var user = User()
        println(user.v) //输出<none>
        user.v = "first change" //输出v: <none> -> first change
        println(user.v) //输出first change
        user.v = "second " //输出v: first change -> second
        println(user.v) //输出first change
        user.v = "third change" //输出v: first change -> third change
        println(user.v) //输出third change
  • Delegates.notNull
    如果这个值在被获取之前没有被分配,它就会抛出 一个异常。
class User {
    var o by Delegates.notNull<String>()
}

user.o = "ooo"
println(user.o) //报错,Caused by: java.lang.IllegalStateException: Property o should be initialized before get.

3. 将多个属性保存在一个map内
使用 map 实例本身作为属性的委托

class User(map: MutableMap<String, Any?>) {
    var id: Long by map
    var name: String by map
}
class Teacher(map: MutableMap<String, Any?>) {
    var id: Long by map
    var name: String by map
}

       var map: MutableMap<String, Any?> = mutableMapOf("name" to "user", "id" to 1)
        var user = User(map)
        var t = Teacher(map)

        println("before change")
        println("user ->${user.id}--${user.name}")
        println("teacher->${t.id}--${t.name}")

        println(" change map id to 850")
        map.set("id", 850)
        println("user ->${user.id}--${user.name}")
        println("teacher->${t.id}--${t.name}")

        println(" change user.name to userchange")
        user.name = "userchange"
        println("user ->${user.id}--${user.name}")
        println("teacher->${t.id}--${t.name}")
        println("map->${map.entries}")
结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容