[英]Kotlin delegate with `by` but create delegate *inside* delegator
我想使用 Kotlin 委托,但我不想在委托人之外创建委托。 委托的所有示例都如下所示:
interface Worker {
fun doWork()
}
class Supervisor(workerDelegate: Worker) : Worker by workerDelegate {
}
class Delegate : Worker {
override fun doWork() {
// actual work
}
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor(delegate)
supervisor.doWork() // delegates to delegate
}
但我想在Supervisor
中创建Delegate
。 像这样的东西:
class Supervisor : Worker by workerDelegate {
init {
val workerDelegate = Delegate()
}
}
这样的事情可能吗?
我想你想要的是这样的:
class Supervisor : Worker by Delegate(){
}
只需使用私有构造函数。
class Supervisor private constructor(workerDelegate: Worker) : Worker by workerDelegate {
constructor() : this(Delegate())
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor()
supervisor.doWork() // delegates to delegate
}
你应该明白两件事:
(..., some:IFace): IFace by some
仅使用 ctor 参数并且仅在创建期间 (,) 而不是在创建之后,它不是“惰性”并且它不绑定“字段”或“属性”它绑定的instance
是在创建时给出。 所以。 这不是预期的“委托”,它只是提示编译器将所有 IFace 调用替换为已经在堆栈中的实例。
而init{...}
是 class 的构造逻辑的一部分,它适用于 class 的成员,但不能by
操作数替换已经从 ctor in 处理的参数。
最先进的方法就是创建“静态”工厂方法来提供一些逻辑来评估 ctor 的参数。
假设这里之前所说的所有这些事情:
package codes.spectrum.serialization_json.excel
import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec
class ItIsNotWorking : StringSpec() {
interface IDo {
fun doIt(): Int
companion object {
val STUB = object :IDo {
override fun doIt(): Int {
error("I am just stub")
}
}
}
}
class Do1 : IDo {
override fun doIt() = 1
}
class Do2 : IDo {
override fun doIt() = 2
}
// i try to make it as parameter in ctor but as var, wishing that it will bind it each call,
// not just during construction
class SuperDo private constructor(param:Int, var doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(param, IDo.STUB)
init {
// here i try some logic to lately (after construction) to setup doiter
if(param % 2 == 1){
doiter = Do1()
}else{
doiter = Do2()
}
}
}
init {
// that is my expectations
"When with 1 it will be Do1" {
SuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
SuperDo(1).doIt() shouldBe 1 // fail!!!
}
"When with 2 it will be Do2" {
SuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
SuperDo(2).doIt() shouldBe 2 //fail!!
}
// Uffff!!!! It's not working at all (!!!)
}
class NotSuperDo private constructor(val doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(buildDoiter(param))
companion object {
fun buildDoiter(param: Int) : IDo =
if(param % 2 == 1){
Do1()
}else{
Do2()
}
}
}
init {
// that is my expectations
"not-super When with 1 it will be Do1" {
NotSuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
NotSuperDo(1).doIt() shouldBe 1 // ok!!!
}
"not-super When with 2 it will be Do2" {
NotSuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
NotSuperDo(2).doIt() shouldBe 2 //ok!!
}
// It worked! But it still just better constructor - not case to substitute delegated iface
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.