Kotlin构造函数委托给内部数据类?

我们有一个抽象的Java类(我们不能修改)叫做AbstractClass ,我们要在Kotlin中实现。 一个要求是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 } } 

(注意MyClass构造函数中by MyClassData显然不起作用)

即我想以某种方式破坏或委托MyClass的构造函数采取与MyClassData相同的参数,而不重复他们。 这是你可以在Kotlin中做的事情,还是有另一种方法来解决它,而不添加太多的代码?

我认为你主要关心的是:(a)简洁的外部API,(b)清洁的内部状态(对于杰克逊)

次要构造函数

这非常精简:

 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) 

Pass-Thru Params&Initializer:

这是我的第一个想法:直接拉出外部类的参数(尽管我现在认为二级构造函数更好,因为它不污染外部类):

 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) 

概念语法:结构化(不存在)

我有点喜欢用于方法论点的“结构化”语法的思想,将输入组合成一个对象(与解构相反); 有点像可变参数(即语法糖):

 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) 

在实践中,这是一个罕见的要求,并且只需要少量额外的字符就可以轻松管理,所以我不认为它会发生。