Kotlin 数据的主要构造函数中的局部参数 class

Local parameters in Kotlin's primary constructor of a data class

关于 data classes 禁止 而不是 在主构造函数中使用 varval 关键字,即 每个 参数都隐式转换为 class 属性。但是,有时我不希望每个参数都变成 class 属性.

因此,据我所知,没有机会在主构造函数中传递只能在构造函数中访问并且在实例构造完成后被遗忘的参数。这有充分的理由吗?

我认为解决这个问题的唯一方法是 使用 data classes 或使用允许 non-var/val-prefixed变量。但是,由于需要传递大量参数,辅助构造函数会极大地膨胀 class。当然,我可以将所有参数包装到另一个对象中,但这只会将问题转移到另一个地方。

是否有推荐的方法或模式来解决这个问题?

我必须说的第一件事是,这是我个人的意见,所以请持保留意见。

来自官方kotlin documentation

We frequently create classes whose main purpose is to hold data. In such a class some standard functionality and utility functions are often mechanically derivable from the data.

所以data classes应该用作数据持有者,它们不应该包含太多逻辑。

从我的角度来看,当您想将某些内容传递给构造函数但 class 不存储该数据时,可能存在一些与之相关的逻辑。

您想要执行此操作的常见情况是:

  1. 使用一些标志来改变构造函数的行为

  2. 传递一些 class 来包装所有需要的数据,然后将其提取到每个单独的字段。

在第一种情况下,我们清楚地看到这不是 data class 用例的一部分。

第二种情况只是糟糕的代码,它引入了对另一个 class 的不必要的依赖并隐藏了 class 实际需要的东西。

构造函数应该很简单,它们获取 class 需要的数据并将其绑定到字段,那里不应该有太多逻辑,应该由那些使用构造函数准备所有数据的人来决定,如果有在创建新实例时是一些可重复的代码,那么使用 factory method 封装它可能是个好主意。

你完全没有限制,你只是要做一些不同的事情。

数据classes旨在非常清楚它们包含什么以及以什么顺序,并且只允许主构造函数参数列表中的成员。

但您还有其他选择:使用 二级构造函数、and/or 创建同名的顶级函数作为具有不同重载的 class,或者在伴随对象中创建 工厂方法

data class Person(val name: String, val age: Int) {
    // secondary constructor
    constructor (name: String): this(name, 0) {
       // ... make a newborn
    }

    // factory methods in companion object
    companion object {
        fun of(name: String, birthdate: LocalDate): Person {
            return Person(name, yearsSince(birthdate))
        }
    }
}

// function with same name as class acting like a constructor
fun Person(name: String, birthdate: LocalDate): Person {
    return Person(name, yearsSince(birthdate))
}

// these all work now:

Person("Fred", 30)                                  // primary constructor
Person("Baby")                                      // secondary constructor
Person("Geoff", LocalDate.parse("12/08/1990"))      // top-level function
Person.of("Jennifer", LocalDate.parse("01/01/1981") // companion function

您还可以通过将其设为私有来隐藏主构造函数,但您无法隐藏该构造函数的 copy 版本。

顺便说一下,让数据 classes 与主构造函数的这个契约一起真正帮助 serialization/deserialization 库知道如何处理 class ,否则这将是猜测。这是好事!