【问题标题】:Partial class delegation in KotlinKotlin 中的部分类委托
【发布时间】:2015-09-03 07:53:46
【问题描述】:

如何在 Kotlin 中部分委托方法/字段?

具体来说:这里我试图从接口TraitA 继承类User 并在包装器StateA 中实现字段marked: Boolean。这将清理User 的实现,因为marked 只是一个状态字段。注意TraitA不能是一个类,因为我想使用几个这样的接口:User() : TraitA by StateA, TraitB by StateB, ..

/* does not compile (Kotlin M12) */
interface TraitA {
    var marked: Boolean

    fun doStaffWithMarked()  // must be overridable
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA(){
    override fum doStaffWithMarked() {
        //...all fancy logic here...
    }
}

另一种方法是在一个地方实现所有功能:

class User() : TraitA{
    override var marked = false // ugly code

    override fum doStaffWithMarked() {
        //...
    }
}

有没有一种方法/模式可以用尽可能简单的代码解决这个问题?代码/字节码生成不是我的选择。

更新

对此我不是很清楚,但请注意doStaffWithMarked() 对于每个User 都是唯一

所以我可能会建议一个带有运行时断言的“半坏”解决方案:

interface TraitA {
    var marked: Boolean

    /* must be overridden */
    fun doStaffWithMarked() = throw UnsupportedOperationException()
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA() {
    override fum doStaffWithMarked() {
        //...all fancy logic here...
    }
}

这个问题仍然悬而未决,因为一个非常好的解决方案会在编译时检查 doStaffWithMarked()

【问题讨论】:

  • TraitA 中的 isMarked() 似乎是多余的。您可以按原样访问标记。
  • isMarked() 做了很多花哨的员工,并且必须为每个最终用户覆盖
  • 我认为这不会很快实现,因为 StateA 并不是一个真正的完整类,如果不提供 doStaffWithMarked() 的实现,就无法实例化它,因此 StateA 本身是无用的。而且有一些像 User 是一个完整的类和 StateA 这是一个不完整的类这样的类非常奇怪,我猜对类型检查会很痛苦

标签: multiple-inheritance delegation kotlin


【解决方案1】:

TraitA 拆分为两个接口,然后委托一个并实现另一个:

interface TraitA {
    var marked: Boolean
}

interface TraitAPlus : TraitA {
    fun isMarked(): Boolean
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA(), TraitAPlus {
    override fun isMarked(): Boolean {
        return marked
    }
}

【讨论】:

  • 在语言级别支持这样的模式会很酷。不过,不确定它会是什么样子。
  • Kotlin 的座右铭是让事情变得明确。我猜编译器可以让你将接口委托给不完整的实现,但是这个解决方案让什么被委托和实现了什么变得一目了然。
【解决方案2】:

这是一个仅继承自 StateA 而不是委托的版本,但这不是很好:

interface TraitA {
    var marked: Boolean

    fun isMarked(): Boolean
}

abstract class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA, StateA() {
    override fun isMarked(): Boolean {
        return marked
    }
}

这是一种有点不寻常的方法,我将TraitA 委托给StateA 的匿名实例

class User() : TraitA by object : StateA() {
    override fun isMarked(): Boolean {
        return marked
    }
} {

}

说实话,我宁愿重新考虑类层次结构的设计。特别是,您可以将方法实现放在接口中(但不能放在属性值中),因此如果isMarked() 仅依赖于marked,您可以直接将其实现放在TraitA 中。然后你的代码变成:

interface TraitA {
    var marked: Boolean

    fun isMarked(): Boolean {
        return marked
    }
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA() {

}

编辑:单独的答案:https://stackoverflow.com/a/30914383/615306

【讨论】:

  • 感谢您的回答。但正如你所说,这些方法不是很好。最后一个不是我需要的,因为isMarked() 应该是可覆盖的(请参阅更新)。第一个带有类的东西扼杀了多继承的整个想法。带有匿名对象的第二个有效,但它是 supper 丑陋的。
  • 我同意。您能否将 TraitA 拆分为两个接口,以便您可以委托其中一个并实现另一个?查看我的编辑。
  • 宾果游戏!它有效,我可以扩展它:try.kotlinlang.org/#/UserProjects/oofhklfiv3hi54r971le3l1tth/…
  • 您能否将最后一个解决方案提取到单独的答案中,以便我将其标记为正确?谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-05-07
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多