我们想要在Kotlin中实现一个名为AbstractClass
的抽象Java类(我们无法修改)。一个要求是Kotlin实现可以使用vanilla Jackson Databind对JSON进行序列化/反序列化。这导致我们进行以下实施:
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
}
}
此类将始终从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
}
}
(请注意by MyClassData
构造函数中的MyClass
显然不起作用)
即。我想以某种方式破坏或委托MyClass的构造函数来获取与MyClassData相同的参数而不重复它们。这是你可以在Kotlin做的事情,还是有另一种解决方法而不添加太多代码?
答案 0 :(得分:2)
我认为您的主要关注点是:(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)
这是我的第一个想法:直接拔出外类&#39; params(虽然我现在认为辅助构造函数更好,因为它不会污染外部类):
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)
我有点喜欢“结构化”的想法。方法参数的语法,用于将输入分组到对象中(与解构相反);有点像varargs(即语法糖):
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)
在实践中,它是一项罕见的要求,并且只需要一些额外的字符就可以轻松管理显式超载,所以我认为它不会发生。