【问题标题】:Kotlin delegate with `by` but create delegate *inside* delegatorKotlin 委托与 `by` 但在 *inside* 委托人中创建委托
【发布时间】:2020-07-22 19:48:04
【问题描述】:

我想使用 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
}

但我想创建Delegate inside Supervisor。像这样的:

class Supervisor : Worker by workerDelegate {
    init {
        val workerDelegate = Delegate()
    }
}

这样的事情可能吗?

【问题讨论】:

    标签: kotlin delegates


    【解决方案1】:

    我想你想要的是这个:

    class Supervisor : Worker by Delegate(){
        
    }
    

    【讨论】:

      【解决方案2】:

      只需使用私有构造函数。

      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
      }
      

      【讨论】:

        【解决方案3】:

        你应该明白两件事:

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

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

        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
        
        
            }
        
        }
        
        猜你喜欢
        • 2011-01-12
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        • 2018-12-31
        • 1970-01-01
        • 2018-05-07
        • 2019-09-08
        相关资源
        最近更新 更多