Kotlin:抽象超类可以有抽象构造函数吗?

6
我刚刚写了这个,就它本身而言还不错:
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.jsonObject
import com.google.gson.JsonElement
import com.google.gson.JsonObject

abstract class BatchJobPayload {
    abstract fun toJson(): JsonObject
}

class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload() {
    constructor(payload: JsonElement) : this(payload["bookingId"].int)

    override fun toJson() = jsonObject(
        "bookingId" to bookingId
    )
}

但是,如果可能的话,我想坚持要求所有扩展BatchJobPayload的类实现一个具有签名constructor(payload: JsonElement): BatchJobPayload的辅助构造函数,用于反序列化。

BookingConfirmationMessagePayload有这样的构造函数,但只是因为我放在那里,而不是因为BatchJobPayload要求这样做...


2
我认为你做不到这个。如果给 BatchJobPayload 添加一个构造函数,那么所有的子类都必须调用这个父类构造函数,但是我认为这并没有什么帮助。 - s1m0nw1
强制要求两个构造函数没有任何意义。如果你宁愿让某人始终传递bookingId,为什么不完全删除默认构造函数呢?那么它还有什么用处呢?相反,可以为其设置一个默认值吗? - Sourabh
@Sourabh 目的是始终有两种方法来创建 BatchJobPayload 的子类:直接使用主构造函数和间接地使用仅具有 JSON 字符串的情况,该字符串是调用现有实例上的 toJson 的结果。请参见序列化 - gtod
2个回答

1
你无法强制执行超级构造函数,但是你可以使用具有 spawn 方法的工厂来强制返回 BatchJobPayload 的子类,这样可以确保类可被构建。
代码示例如下:
class JsonObject // Included to make compiler happy

abstract class Factory<T> {
    abstract fun make(obj: JsonObject): T
}

abstract class Base {
    abstract fun toJson(): JsonObject
}


class A(val data:JsonObject):Base() {
    override fun toJson(): JsonObject {
        return JsonObject()
    }
}

class AFactory: Factory<A>() {
    override fun make(obj: JsonObject): A {
        return A(obj)
    }

}

fun main(args: Array<String>) {
    val dummyJson = JsonObject()

    var factory = AFactory()
    var instance = factory.make(dummyJson)

    println(instance)
}

我无法让这段代码运行。我不确定是否可以像上面展示的那样在Kotlin中使用类型参数构造对象:return A(obj)... - gtod
@gtod,我添加了一个主方法来展示如何使用它,在我的端上成功运行了,你遇到了什么问题? - jrtapsell
抱歉 @jrtapsell,你是对的,我已经按照你的方法解决了问题: - gtod
没问题,我应该从一开始就包括主方法。 - jrtapsell
实际上,我将A的定义更改为class A(val id: Int) : Base() {,并且在AFactory中,override现在是override fun make(obj: JsonObject) = A(obj["id"].int)。这个方法可以工作,但是因为通常情况下,AB等类需要自己独特的构造函数,那么类型参数有什么意义呢(您看过我自己的答案吗?它没有使用类型参数)? - gtod

1
我想到的可行选项如下:

interface BatchJobPayload {
    fun toJson(): JsonObject
}

interface BatchJobPayloadDeserialize {
    operator fun invoke(payload: JsonElement): BatchJobPayload
}

class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload {
    override fun toJson() = jsonObject(
        "bookingId" to bookingId
    )
}

class BookingConfirmationMessagePayloadDeserialize : BatchJobPayloadDeserialize {
    override operator fun invoke(payload: JsonElement) =
        BookingConfirmationMessagePayload(payload["bookingId"].int)
}

现在,您可以按照以下方式从JsonElement反序列化一个BookingConfirmationMessagePayload对象:
BookingConfirmationMessagePayloadDeserialize()(payload)

(The invoke 操作符只是一些语法糖,可能有点晦涩...)
实际上,我仍然更喜欢原始代码,因为它不那么冗长 --- 未来需要子类化 BatchJobPayload 的开发人员可能最初会忽略定义一个接受 JsonElement 的构造函数,但是一旦他们只有一串需要将其转换为新类实例的 JSON 字符串,他们肯定会意识到自己的遗漏...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接