【问题标题】:Kotlin Calling Companion Object in Abstract ClassKotlin 在抽象类中调用伴侣对象
【发布时间】:2021-07-09 02:11:25
【问题描述】:

我有一个类,Base,它是一个抽象类,定义为:

abstract class Base() {}

我想从这个基类创建一些派生类:

class A : Base() {}
class B : Base() {}
class C : Base() {}

我希望能够调用一个通用函数create,该函数执行一些初始化工作并返回指定的派生类(例如A)。例如,如下所示是理想的:

val a = A.create() // `a` now holds an instance of `A`.
val b = B.create()
val c = C.create()

最初我尝试在抽象类中使用伴随对象作为一种静态函数:

abstract class Base {
    companion object {
        fun create() : Base { 
            // Do some initialization and return the derived class
            // of the object. Obviously I can't return `Base` as I've
            // indicated above since it is an abstract class. This is
            // what I'm confused about: How do I return a copy of the
            // _derived_ class here? Is this impossible? I think it
            // might be...
            return Base() // <-- This doesn't work. What should be returned?
        }
    }
}

然后在派生类中:

class A : Base() {
    companion object {
        fun create() : A = Base.create()
    }
}

这不起作用,原因很明显。也就是说,我无法返回抽象类Base 的实例。有没有一种简单的方法来完成var a = A.create() 范式? create 的代码在派生类中是相同的,所以我想避免在我创建的每个类中重新创建功能。

【问题讨论】:

  • "创建的代码在派生类中是相同的" 那么,怎么可能呢?如果代码完全相同,则返回类型也完全相同。
  • @AlexeyRomanov 这就是我的意思。返回类型是从Base 继承的。也许更好的措辞是“create 的样板代码每次都需要做同样的事情,但针对不同的派生类”。我无法创建返回类型 Base,因为这意味着创建派生类的实例。

标签: java kotlin


【解决方案1】:

如果初始化逻辑相同并且基于Base类中指定的功能,您也可以这样做:

abstract class Base() {

    protected fun init(): Base {
        // do the initialization
        return this
    }
}

class A : Base() {
    companion object {
        fun create() = A().init() as A
    }
}

【讨论】:

    【解决方案2】:
    abstract class Base {
        companion object {
            inline fun <reified T : Base> create() : T { 
                // you can use T::class here
            }
        }
    }
    
    class A : Base() {
        companion object {
            fun create() : A = Base.create() // inferred to Base.create<A>()
        }
    }
    

    可能有效,但可能需要使用不安全的反射。这取决于你到底想在create 中做什么......更好的做法是将类之间的任何不同作为函数传递,例如

    abstract class Base {
        companion object {
            inline fun <reified T : Base> create(f: () -> T) : T { 
                val instance = f()
                // do something
                return instance // or something created from it
            }
        }
    }
    
    class A : Base() {
        companion object {
            fun create() : A = Base.create { A() }
        }
    }
    

    【讨论】:

    • 谢谢!基于这个答案,我可以制作自己的内联具体化伴随函数来创建我的项目实例,而不会出现不安全的反射!
    【解决方案3】:

    我假设你的类共享一个具有相同参数列表的构造函数。 然后你可以做的是定义一个特征

    trait Instantiation[K] {
    
      def newWith(args):K
    }
    

    让你的类实现这个

    class A implements Instantiation[A] {
      override def newWith(args):A
    }
    
    class B implements Instantiation[B] {
      override def newWith(args):B
    }
    
    class C implements Instantiation[C] {
      override def newWith(args):C
    }
    

    现在在共享逻辑中你可以调用 newWith() 来返回正确的类型

    【讨论】:

    • OP 询问的是 Kotlin,而不是 Scala(您的答案似乎正在使用)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    相关资源
    最近更新 更多