Kotlin 构造函数委托给内部数据 class?
Kotlin constructor delegation to inner data class?
我们有一个名为 AbstractClass
的抽象 Java class(我们无法修改),我们想在 Kotlin 中实现它。一个要求是 Kotlin 实现是 serializable/deserializable 到 JSON 使用 vanilla Jackson Databind。这导致我们进行了以下实施:
class MyClass(private val data: MyClassData? = null) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
override fun getData(): MyClassData? {
return data
}
}
此 class 将始终从 Java 使用,目前您可以像这样实例化它 (Java):
MyClass myClass = new MyClass(new MyClassData("John Doe", 25));
但我们更愿意像这样实例化它:
MyClass myClass = new MyClass("John Doe", 25);
我当然可以将 Kotlin 代码改成这样:
class MyClass(@JsonIgnore private var name: String = "", @JsonIgnore private var age: Int = 0) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
private var data : MyClassData? = null
init {
data = MyClassData(name, age)
}
override fun getData(): MyClassData? {
return data
}
}
但这非常冗长,有点违背了使用 Kotlin 的目的。
我想我想做的是这样的(伪代码):
class MyClass(private val data: MyClassData? = null by MyClassData) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
override fun getData(): MyClassData? {
return data
}
}
(注意 MyClass
构造函数中的 by MyClassData
显然不起作用)
即我想以某种方式破坏或委托 MyClass 的构造函数以采用与 MyClassData 相同的参数而不复制它们。这是您可以在 Kotlin 中做的事情,还是有另一种方法可以在不添加太多代码的情况下解决它?
我认为您主要关心的是:(a) 简洁的外部 API,(b) 干净的内部状态(对于 Jackson)
二级构造函数
这很瘦:
class MyClass internal constructor(private val data: MyClassData)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
constructor(name: String, age: Int) : this(MyClassData(name, age))
override fun getData(): MyClassData? = data
}
无需创建额外字段的简单 API(尽管我认为此语法具有误导性):
val myClass = MyClass("John Doe", 25)
传递参数和初始化程序:
这是我的第一个想法:直接拉出外部class'参数(虽然我现在认为辅助构造函数更好,因为它不会污染外部class):
class MyClass(@JsonIgnore private val name: String, @JsonIgnore private val age: Int)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
private val data = MyClassData(this@MyClass.name, this@MyClass.age)
override fun getData(): MyClassData? = data
}
...再次,相同 API:
val myClass = MyClass("John Doe", 25)
自营工厂
这种方法可能具有更具描述性的语法:
class MyClass(private val data : MyClassData)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
companion object Factory {
fun create(name: String, age: Int) = MyClass(MyClassData(name, age))
}
override fun getData(): MyClassData? = data
}
可以这样调用:
val myClass = MyClass.Factory.create("John Doe", 25)
概念语法:结构化(不存在)
我有点喜欢方法参数的 'structuring' 语法的想法,它将输入分组到一个对象中(与解构相反);有点像可变参数(即语法糖):
class MyClass(
private val data: (name: String, age: Int) : MyClassData(name, age)
) { ... }
可以通过以下两种方式调用:
val myClass1 = MyClass(MyClassData("John Doe", 25))
val myClass2 = MyClass("John Doe", 25)
在实践中,这是一个罕见的要求,并且只需几个额外的字符就可以通过显式重载轻松管理,所以我认为它永远不会发生。
我们有一个名为 AbstractClass
的抽象 Java class(我们无法修改),我们想在 Kotlin 中实现它。一个要求是 Kotlin 实现是 serializable/deserializable 到 JSON 使用 vanilla Jackson Databind。这导致我们进行了以下实施:
class MyClass(private val data: MyClassData? = null) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
override fun getData(): MyClassData? {
return data
}
}
此 class 将始终从 Java 使用,目前您可以像这样实例化它 (Java):
MyClass myClass = new MyClass(new MyClassData("John Doe", 25));
但我们更愿意像这样实例化它:
MyClass myClass = new MyClass("John Doe", 25);
我当然可以将 Kotlin 代码改成这样:
class MyClass(@JsonIgnore private var name: String = "", @JsonIgnore private var age: Int = 0) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
private var data : MyClassData? = null
init {
data = MyClassData(name, age)
}
override fun getData(): MyClassData? {
return data
}
}
但这非常冗长,有点违背了使用 Kotlin 的目的。
我想我想做的是这样的(伪代码):
class MyClass(private val data: MyClassData? = null by MyClassData) : AbstractClass<MyClassData>(MyClass::class.java, "1") {
data class MyClassData(var name: String = "", var age: Int = 0) : AbstractData
override fun getData(): MyClassData? {
return data
}
}
(注意 MyClass
构造函数中的 by MyClassData
显然不起作用)
即我想以某种方式破坏或委托 MyClass 的构造函数以采用与 MyClassData 相同的参数而不复制它们。这是您可以在 Kotlin 中做的事情,还是有另一种方法可以在不添加太多代码的情况下解决它?
我认为您主要关心的是:(a) 简洁的外部 API,(b) 干净的内部状态(对于 Jackson)
二级构造函数
这很瘦:
class MyClass internal constructor(private val data: MyClassData)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
constructor(name: String, age: Int) : this(MyClassData(name, age))
override fun getData(): MyClassData? = data
}
无需创建额外字段的简单 API(尽管我认为此语法具有误导性):
val myClass = MyClass("John Doe", 25)
传递参数和初始化程序:
这是我的第一个想法:直接拉出外部class'参数(虽然我现在认为辅助构造函数更好,因为它不会污染外部class):
class MyClass(@JsonIgnore private val name: String, @JsonIgnore private val age: Int)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
private val data = MyClassData(this@MyClass.name, this@MyClass.age)
override fun getData(): MyClassData? = data
}
...再次,相同 API:
val myClass = MyClass("John Doe", 25)
自营工厂
这种方法可能具有更具描述性的语法:
class MyClass(private val data : MyClassData)
: AbstractClass<MyClass>(MyClass::class.java, "1") {
data class MyClassData(var name: String, var age: Int) : AbstractData
companion object Factory {
fun create(name: String, age: Int) = MyClass(MyClassData(name, age))
}
override fun getData(): MyClassData? = data
}
可以这样调用:
val myClass = MyClass.Factory.create("John Doe", 25)
概念语法:结构化(不存在)
我有点喜欢方法参数的 'structuring' 语法的想法,它将输入分组到一个对象中(与解构相反);有点像可变参数(即语法糖):
class MyClass(
private val data: (name: String, age: Int) : MyClassData(name, age)
) { ... }
可以通过以下两种方式调用:
val myClass1 = MyClass(MyClassData("John Doe", 25))
val myClass2 = MyClass("John Doe", 25)
在实践中,这是一个罕见的要求,并且只需几个额外的字符就可以通过显式重载轻松管理,所以我认为它永远不会发生。