【问题标题】:Reference outside the sealed class in Kotlin?在 Kotlin 的密封类之外引用?
【发布时间】:2017-11-18 00:38:10
【问题描述】:

我正在尝试创建一个类,它使用自己的状态来操作它所引用的外部对象的状态。外部对象可以是 A 类或 B 类,它们是相似的,但不受作者控制。因此,根据this earlier answer from @SimY4,创建了一个密封类来访问它们的公共属性。

// *** DOES NOT COMPILE ***
class A {   // foreign class whose structure is not modifiable
  val prop get()= "some string made the Class-A way"
}
class B {   // foreign class whose structure is not modifiable
  val prop get()= "some string made the Class-B way"
}
data class ABTool (val obj:AB, val i:Int, val j:Int) {
  // class that manipulates i and j and uses them to do
  // things with AB's "common" attributes through the sealed class AB
  sealed class AB {   // substitute for a common interface
    abstract val prop: String
    abstract val addmagic: String
    data class BoxA(val o:A) : AB() {
      override val prop get()= o.prop
      override val addmagic get() = prop + this@???.magic  // HOW TO REFERENCE?
    }
    data class BoxB(val o:B) : AB() {
      override val prop get()= o.prop
      override val addmagic get() = this@???.magic + prop  // HOW TO REFERENCE?
    }
  }
  val magic get()= "magic: ${i*j}"
}

现在的问题是我发现我不能以我想要的方式操作外部对象,因为密封类不能引用它的外部类成员。有没有更好的方法来完成这项工作,即使使用不同的方法(除了密封类),同时:

  • 不更改外国 A 或 B 类;
  • 考虑到 A 和 B(以及真实案例中的许多其他)是相似的,所以我正在尝试编写一个工具来计算并使用相同的代码库为 A 和 B 添加魔法;和
  • 请注意,尽管 ABTool 工具是相同的,但它们用于添加魔法的方式在 A 和 B 中略有不同,就像访问 A 和 B 的概念上通用元素的方式可能不同一样。

对此或类似的解决方法有什么想法吗?也许是我还没有想到的更实用的方法?

【问题讨论】:

    标签: kotlin abstract-class inner-classes sealed data-class


    【解决方案1】:

    如果ABTool 作为一个密封类是你可以放弃的,那么这里有一个解决方案:

    1. ABTool 声明中将sealed 替换为inner abstract
    2. 也将BoxABoxB 标记为inner

    data class ABTool(val obj: AB, val i: Int, val j: Int) {
        inner abstract class AB {
            abstract val prop: String
            abstract val addmagic: String
    
            inner class BoxA(val o: A) : AB() {
                override val prop get() = o.prop
                override val addmagic get() = prop + magic
            }
    
            inner class BoxB(val o: B) : AB() {
                override val prop get() = o.prop
                override val addmagic get() = magic + prop
            }
        }
    
        val magic get() = "magic: ${i * j}"
    }
    

    (或者,不要将AB 标记为内部,而是将BoxABoxB 移出它到ABTool 的范围内)

    【讨论】:

    • 我对如何实例化感到困惑。给定val a=A(),我试过ABTool.AB.BoxA(a)。我认为BoxA 想让我实例化AB,可能是因为BoxA 是内部的? ABTool.AB().BoxA(a) 不起作用,可能是因为 AB 是抽象的? ABTool().AB().BoxA(a) 不起作用,可能是因为 ABTool 需要构造函数?...但是构建它是我首先要做的。我是否错过了这需要在同伴类或其他东西中? 你能帮我理解如何实例化它吗?谢谢。
    • 确实,这很复杂。 ABTool 的主构造函数中是否需要 val obj: AB?当它在那里时,您需要在创建ABTool 之前创建一个ABBoxABoxB),但由于它们是inner,因此它们需要一个ABTool 实例当时存在。
    • 暂时忘记外部数据类,这是我无法理解的更简单的部分......如果BoxABoxB的构造函数(因为它们是inner)依赖于AB 的instance 可见,AB 类型的对象实例只能通过创建BoxABoxB 来创建(因为AB 是抽象的并且BoxABoxB 是唯一具有 AB 作为超类的类)......它们可以被实例化吗? (我一直认为我在理解内部类时缺少一个关键环节......)
    • 由于抽象类中的内部类本身可能是一个有用的答案,I started a new question
    【解决方案2】:

    另一种方法是将ABTool 字段添加到AB

    sealed class AB(val tool: ABTool) {
      abstract val prop: String
      abstract val addmagic: String
      data class BoxA(val o:A, tool: ABTool) : AB(tool) {
        override val prop get()= o.prop
        override val addmagic get() = prop + tool.magic
      }
      data class BoxB(val o:B, tool: ABTool) : AB(tool) {
        override val prop get()= o.prop
        override val addmagic get() = tool.magic + prop
      }
    }
    

    并在从ABTool 创建它时传递this。毕竟,这正是inner 真正做的事情。

    在这种特定情况下,该字段恰好在 AB 本身中未使用,因此您可以将其从那里删除并在 BoxABoxB 中设置为 val

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多