繁体   English   中英

Kotlin 使用 `by` 委托,但在 *inside* 委托人中创建委托

[英]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
}

你应该明白两件事:

  1. (..., some:IFace): IFace by some仅使用 ctor 参数并且仅在创建期间 (,) 而不是在创建之后,它不是“惰性”并且它不绑定“字段”或“属性”它绑定的instance是在创建时给出。 所以。 这不是预期的“委托”,它只是提示编译器将所有 IFace 调用替换为已经在堆栈中的实例。

  2. init{...}是 class 的构造逻辑的一部分,它适用于 class 的成员,但不能by操作数替换已经从 ctor in 处理的参数。

  3. 最先进的方法就是创建“静态”工厂方法来提供一些逻辑来评估 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM