从 Java 代码构造 Kotlin class 实例
Constructing instance of Kotlin class from Java code
我有一个包含 15 个字段的 Kotlin 数据 class。当我使用主构造函数在我的 Kotlin 代码中构造此 class 的实例时,我可以利用有用的功能,例如:
- 省略具有默认值的字段
- 使用命名参数
但是,当从 Java 代码构建此 Kotlin class 的实例时,我面临着这样一个事实,即我需要在构造函数中以正确的顺序提供所有 15 个参数,而无需命名它们的能力。当这个 Java 代码是一个单元测试时,这尤其不方便,我对填写所有这些字段并不感兴趣,但只有一两个对测试有用。
当纯粹使用 Java 时,我不会遇到这个问题,因为我会使用 (Lombok) 构建器来构造对象的实例,可以灵活地只提供我感兴趣的字段英寸
有没有办法缓解这个问题,或者这是我混合使用 Java 和 Kotlin 必须付出的代价?
Is there a way to mitigate this problem...
有点,但它不是 out-of-the-box 解决方案。下面详细介绍它。
... is this the price I have to pay for mixing Java and Kotlin?
不,不是。如果我们解决这个问题,您会注意到 Java 无法提供默认值,因此在与 Kotlin 一起使用时不方便。构造复杂对象是Builder Pattern存在的主要原因。但是 Kotlin 为我们提供了一个解决方案,可以避免大多数与构造复杂对象相关的问题,并使构建器模式过时。
如何处理?
没有一种解决方案,而是多种解决方案。我会列出至少两个我马上想到的:
- 一级+二级构造;
- 工厂。
一级+二级构造
使用这个选项,你可以创建一个包含整个列表的主构造函数
您的 class 应该持有的参数并引入一个辅助构造函数,该构造函数 只接受必需的值或默认情况下无法设置的值 :
class Example(val param1: Any, val param2: Any? = null, val param3: Any? = null) {
// In this situation we have to use different argument names
// to make explicit use of primary constructor.
// e.g. if we remove `param1 = ` or rename `requiredParam` to `param1`
// we will get an error saying: "There's a cycle in the delegation calls chain"
constructor(requiredParam: Any) : this(param1 = requiredParam)
}
工厂
对于工厂来说,一切看起来都差不多。虽然,此解决方案 在 Java 中会更加冗长,但它 消除了使用命名参数 的需要,并为我们提供了 在对象初始化之前可以自由地做更多的准备工作。 我们甚至可以让它异步(就像是网络调用一样)!
class Example(val param1: Any, val param2: Any? = null, val param3: Any? = null) {
object Factory {
fun from(param1: Any): Example {
return Example(param1)
}
}
}
结论
没有“正确”的解决方案。我们可以选一个我们喜欢的,也可以想出一个新的。
- 一级+二级构造函数:
- (+) 从 Java;
使用时更简洁
- (-) 如果辅助构造函数发生变化,您将必须更新 Java 代码;
- (-) 构造函数参数需要不同的名称。
- 工厂:
- (+) 提供更多自由:例如你可以在
from
函数中计算一些东西,与构造函数相比它会更具可读性;
- (+) 隐藏构造函数实现。您以后可以更改构造函数而无需修改任何 Java 代码或工厂函数;
- (-) 在 Java.
中使用时会更加冗长
我有一个包含 15 个字段的 Kotlin 数据 class。当我使用主构造函数在我的 Kotlin 代码中构造此 class 的实例时,我可以利用有用的功能,例如:
- 省略具有默认值的字段
- 使用命名参数
但是,当从 Java 代码构建此 Kotlin class 的实例时,我面临着这样一个事实,即我需要在构造函数中以正确的顺序提供所有 15 个参数,而无需命名它们的能力。当这个 Java 代码是一个单元测试时,这尤其不方便,我对填写所有这些字段并不感兴趣,但只有一两个对测试有用。
当纯粹使用 Java 时,我不会遇到这个问题,因为我会使用 (Lombok) 构建器来构造对象的实例,可以灵活地只提供我感兴趣的字段英寸
有没有办法缓解这个问题,或者这是我混合使用 Java 和 Kotlin 必须付出的代价?
Is there a way to mitigate this problem...
有点,但它不是 out-of-the-box 解决方案。下面详细介绍它。
... is this the price I have to pay for mixing Java and Kotlin?
不,不是。如果我们解决这个问题,您会注意到 Java 无法提供默认值,因此在与 Kotlin 一起使用时不方便。构造复杂对象是Builder Pattern存在的主要原因。但是 Kotlin 为我们提供了一个解决方案,可以避免大多数与构造复杂对象相关的问题,并使构建器模式过时。
如何处理?
没有一种解决方案,而是多种解决方案。我会列出至少两个我马上想到的:
- 一级+二级构造;
- 工厂。
一级+二级构造
使用这个选项,你可以创建一个包含整个列表的主构造函数 您的 class 应该持有的参数并引入一个辅助构造函数,该构造函数 只接受必需的值或默认情况下无法设置的值 :
class Example(val param1: Any, val param2: Any? = null, val param3: Any? = null) {
// In this situation we have to use different argument names
// to make explicit use of primary constructor.
// e.g. if we remove `param1 = ` or rename `requiredParam` to `param1`
// we will get an error saying: "There's a cycle in the delegation calls chain"
constructor(requiredParam: Any) : this(param1 = requiredParam)
}
工厂
对于工厂来说,一切看起来都差不多。虽然,此解决方案 在 Java 中会更加冗长,但它 消除了使用命名参数 的需要,并为我们提供了 在对象初始化之前可以自由地做更多的准备工作。 我们甚至可以让它异步(就像是网络调用一样)!
class Example(val param1: Any, val param2: Any? = null, val param3: Any? = null) {
object Factory {
fun from(param1: Any): Example {
return Example(param1)
}
}
}
结论
没有“正确”的解决方案。我们可以选一个我们喜欢的,也可以想出一个新的。
- 一级+二级构造函数:
- (+) 从 Java; 使用时更简洁
- (-) 如果辅助构造函数发生变化,您将必须更新 Java 代码;
- (-) 构造函数参数需要不同的名称。
- 工厂:
- (+) 提供更多自由:例如你可以在
from
函数中计算一些东西,与构造函数相比它会更具可读性; - (+) 隐藏构造函数实现。您以后可以更改构造函数而无需修改任何 Java 代码或工厂函数;
- (-) 在 Java. 中使用时会更加冗长
- (+) 提供更多自由:例如你可以在