关于data
类,禁止在主要构造函数中不使用var
或val
关键字,即 every 被隐式地转换为类属性。但是,有时在某些情况下,我不希望每个参数都变成类属性。
据我所知,没有机会在主构造函数中传递参数,该参数只能在构造函数内访问,并且在实例构造完成后会被遗忘。有充分的理由吗?
我想解决这个问题的唯一方法是不使用data
类或使用允许使用非var / val前缀变量的辅助构造函数。但是,由于需要传递大量参数,因此辅助构造函数将极大地膨胀该类。当然,我可以将所有参数包装到另一个对象中,但这只会将问题转移到另一个地方。
是否有建议的方法或模式来应对?
答案 0 :(得分:2)
您完全不受限制,您只需要做一些不同的事情即可。
数据类旨在非常清楚它们包含的内容和顺序,并且仅允许主要构造函数参数列表中的成员。
但是您还有其他选择:使用次要构造函数,和/或创建顶级函数,其名称与具有不同重载的类的名称相同,或者创建<伴侣对象中的strong>工厂方法:
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
版本。
顺便说一句,为主要构造函数使用具有此合同的数据类确实有助于序列化/反序列化库知道如何处理该类,否则将是猜测。这是一件好事!
答案 1 :(得分:0)
我必须要说的第一句话是这是我个人的观点,因此请与盐同食。
来自官方科特琳documentation
我们经常创建主要目的是保存数据的类。在此类中,通常可以从数据中机械地得出一些标准功能和实用功能。
因此,data classes
应该用作数据持有者,并且它们不应包含太多逻辑。
从我的角度来看,当您想将某些内容传递给构造函数但类不存储该数据时,则可能存在与此相关的逻辑。
常见的情况是:
使用一些标志来更改构造函数的行为
传递一些包装所有所需数据的类,然后将其提取到每个单独的字段中。
在第一种情况下,我们可以清楚地看到这不是data class
用例的一部分。
第二种情况只是错误的代码,它引入了对另一个类的不必要依赖,并隐藏了该类实际需要的东西。
构造函数应该简单,它们接收类所需的数据并将其绑定到字段,其中不应包含太多逻辑,应该由使用构造函数来准备所有数据的那些逻辑决定,并且在创建时是否存在一些可重复的代码新实例,那么最好使用factory method
进行封装。