kotlin 委托

我们经常使用的其实是继承,但是相对于继承使用委托的耦合性会更低。

使用继承则代码相对会比较简单,但是使用委托则会比较复杂

一、假设有interface Worker、class JavaProgrammer: Worker、class CShapeProgrammer: Worker三个类;然后新增一个经理类:Manager,经理的技能可能是会java也有可能是会C#也有可能两个都会。如果使用继承的话则需要创建两个经理类,代码太冗余;那么这里可以使用委托的方式,如下所示

复制代码
interface Worker {
    fun work()
    fun takeVacation()
}

class JavaProgrammer: Worker {
    override fun work() = println("...write java")
    override fun takeVacation() = println("...code at beach")
}

class CShapeProgrammer: Worker {
    override fun work() = println("...write c#")
    override fun takeVacation() = println("...branch at ranch")
}

class Manager(val staff: Worker): Worker by staff {
    fun meeting() = println("meeting with ${staff.javaClass.simpleName}")

    override fun takeVacation() = println("of course")
}

val doe = Manager(CShapeProgrammer())
复制代码

如上所示的委托方式,Manager通过传入的是C#还是java来确定委托的是哪个类,并且通过Worker by staff来实现委托(by关键字)

该委托很像继承通过by 实现类;来确定“继承的是哪个父类”, 同时Manager 继承可见的接口是Worker

 

二、如一上所述,如果经理同时委托俩该如何处理

复制代码
interface Worker {
    fun work()
    fun takeVacation()
    fun fileTimeSheet() = println("Why? Really?")
}

class JavaProgrammer: Worker {
    override fun work() = println("...write java")
    override fun takeVacation() = println("...code at beach")
}

class CShapeProgrammer: Worker {
    override fun work() = println("...write c#")
    override fun takeVacation() = println("...branch at ranch")
}

interface Assistant {
    fun doChores()
    fun fileTimeSheet() = println("No escape from that")
}

class DepartmentAssistant: Assistant {
    override fun doChores() = println("route DepartmentAssistant")
}

class Manager(val staff: Worker, val assistant: Assistant): Worker by staff, Assistant by assistant {
    override fun takeVacation() = println("of course")

    override fun fileTimeSheet() {
        println("manally forwarding this....")
        assistant.fileTimeSheet()
    }
}

val doe = Manager(CShapeProgrammer(), DepartmentAssistant())
复制代码

如上所示,Worker和Assistant同时存在接口fileTimeSheet,此时必须要重写该函数否则会出现冲突的情况

因为代理也算是继承,所以如上的doe可以有如下的赋值

val worker: Worker = doe
val assistant: Assistant = doe
worker.work() //No escape from that
worker.fileTimeSheet() //route DepartmentAssistant
assistant.doChores() //manally forwarding this....
assistant.fileTimeSheet()//No escape from that

如上可以看到,worker或者是assistant都是属于Manager类,他们调用的接口显示上跟多态是一致的

 

三、关于设值的委托

如果相对参数的设值底层进行特殊处理,则可以使用设值委托

复制代码
import kotlin.reflect.KProperty

class PoliteString(var content: String) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = 
    content.replace("stupid", "sXXXXdddddX")

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        content = value
    }
}

var comment: String by PoliteString("some nice message") // 这里String使用PoliteString进行委托
println(comment) //some nice message

comment = "this is stupid"
println(comment) //this is sXXXXdddddX 这里将stuipid过滤
println(comment.length) //19 这里使用过滤后的值进行计算长度

fun beingpolite(content: String) = PoliteString(content)
var comment1: String by beingpolite("kkqqq stupid")
println(comment1)
复制代码

 

 

四、关于懒操作

为了程序的顺序操作,可能某些参数计算了但是因为if等原因导致该参数最后没有被用到;如果说没被用到就不进行对该参数的计算,那么会大大节省很多时间

复制代码
fun getTemperature(city: String): Double {
    println("fetch from webservice for $city")
    return 30.0
}

val showTemperature = false
val city = "Boulder"
val temperature by lazy {getTemperature(city)}

if (showTemperature && temperature > 20)
    println("Warm")
else
    println("nothing to")
复制代码

如上,当showTemperature为false的时候,不需要计算temperature的值;这里使用了by lazy的方式,后面接一个lambda表达式,当确实要用到该参数的时候再调用该lambda表达式

 

五关于属性值变化的监听

1、当值变化的时候想要做一些额外的操作,则可以用observable的代理

复制代码
var count by observable(0) {
    property, oldValue, newValue ->

    println("Property: $property  old: $oldValue, new: $newValue")
}
println("The new value count = $count")
++count
println("The new value count = $count")
++count
println("The new value count = $count")
复制代码

如上的输出如下所示:

The new value count = 0

Property: var Observe.count: kotlin.Int  old: 0, new: 1

The new value count = 1

Property: var Observe.count: kotlin.Int  old: 1, new: 2

The new value count = 2

如上所示,每一个的值的变更都会调用该observable对应的lambda表达式

 

2、当拒绝某个参数的赋值时候,可以使用如下

复制代码
var max by vetoable(0) {
    property, oldValue, newValue ->

    oldValue < newValue
}

println("The new value max = $max")
max = 10
println("The new value max = $max")
max = 4
println("The new value max = $max")
复制代码

如下的输出:

The new value max = 0

The new value max = 10

The new value max = 10

当最后一次赋值为4的时候,因为vetoable返回了false则拒绝赋值

 

posted @   LCAC  阅读(94)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示