重复使用Kotlin中不可变数据类的映射代码
更新:添加了评论中的一些澄清 我想对不可变的重复使用Kotlin中不可变数据类的映射代码,kotlin,immutability,Kotlin,Immutability,更新:添加了评论中的一些澄清 我想对不可变的数据类的主构造函数和copy()方法使用相同的“映射”代码。如果不先创建一个空对象,然后在其上使用copy(),我如何才能做到这一点 现在的问题是,如果我向Employee和EmployeeForm添加一个具有默认值的新属性,那么很容易只将其添加到两个映射函数中的一个,而忽略另一个(ToEmployeeNotreurable/copyEmployee) 以下是我想要映射的数据类: @Entity data class Employee( val
数据类的主构造函数和copy()
方法使用相同的“映射”代码。如果不先创建一个空对象,然后在其上使用copy()
,我如何才能做到这一点
现在的问题是,如果我向Employee
和EmployeeForm
添加一个具有默认值的新属性,那么很容易只将其添加到两个映射函数中的一个,而忽略另一个(ToEmployeeNotreurable
/copyEmployee
)
以下是我想要映射的数据类:
@Entity
data class Employee(
val firstName: String,
val lastName: String,
val jobType: Int,
@OneToMany(mappedBy = "employee", cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
private val _absences: MutableSet<Absence> = mutableSetOf(),
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0 // prevents @Joffrey's answer from working
) {
init {
_absences.forEach { it.employee = this }
}
val absences get() = _absences.toSet()
fun addAbsence(newAbsence: Absence) {
newAbsence.employee = this
_absences += newAbsence
}
@Entity
@Table(name = "absence")
data class Absence(
// ... omitted fields
) {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "employee_id")
lateinit var employee: Employee
}
}
data class EmployeeForm(
var firstName: String = "",
var lastName: String = "",
var jobType: Int = 0
) {
// not reusable
fun toEmployeeNotReusable(): Employee {
return Employee(firstName, lastName, jobType)
}
// works but hacky
fun toEmployee(): Employee {
return copyEmployee(Employee("", "", 0))
}
fun copyEmployee(employee: Employee): Employee {
return employee.copy(
firstName = firstName,
lastName = lastName,
jobType = jobType
)
}
}
@实体
数据类雇员(
val firstName:String,
val lastName:String,
val作业类型:Int,
@OneToMany(mappedBy=“employee”,cascade=[CascadeType.ALL],fetch=FetchType.EAGER)
private val_缺席:MutableSet=mutableSetOf(),
@Id@GeneratedValue(策略=GenerationType.IDENTITY)
var id:Long=0//阻止@Joffrey的答案工作
) {
初始化{
_absences.forEach{it.employee=this}
}
val absences get()=\u absences.toSet()
娱乐添加缺席(新缺席:缺席){
newidence.employee=此
_缺勤+=新缺勤
}
@实体
@表(name=“缺勤”)
数据类缺失(
//…省略字段
) {
@manytone(fetch=FetchType.EAGER)
@JoinColumn(name=“employee\u id”)
lateinit var雇员:雇员
}
}
数据类EmployeeForm(
var firstName:String=“”,
var lastName:String=“”,
变量作业类型:Int=0
) {
//不可重复使用
员工乐趣不可编辑():员工{
返回员工(名字、姓氏、职务类型)
}
//工作,但黑客
员工乐趣():员工{
返回copyEmployee(员工(“,”,0))
}
员工(员工:员工):员工{
返回employee.copy(
firstName=firstName,
lastName=lastName,
jobType=作业类型
)
}
}
虽然可变性很好,但在我的例子中,我想知道这是如何实现的。避免将属性列出4次的一种方法是将Employee
声明为接口,并使用“可变性”版本表单作为实现它的唯一数据类。您可以使用该接口获得“只读”视图,但从技术上讲,您只能在幕后使用可变实例
这将遵循Kotlin设计师为List
vsMutableList
所做的工作
interface Employee {
val firstName: String
val lastName: String
val jobType: Int
}
data class EmployeeForm(
override var firstName: String = "",
override var lastName: String = "",
override var jobType: Int = 0
): Employee {
fun toEmployee(): Employee = this.copy()
fun copyEmployee(employee: Employee): Employee = this.copy(
firstName = firstName,
lastName = lastName,
jobType = jobType
)
}
但是,这意味着表单包含员工的所有字段,这可能是您不想要的
另外,我个人更喜欢您在开始时所做的,两次列出字段不会有问题,只需为您的函数编写测试,当您想要添加功能时,无论如何,您都要为该功能添加测试。避免4次列出属性的一种方法是将Employee
声明为接口,并使用“可变”版本表单作为实现它的唯一数据类。您可以使用该接口获得“只读”视图,但从技术上讲,您只能在幕后使用可变实例
这将遵循Kotlin设计师为List
vsMutableList
所做的工作
interface Employee {
val firstName: String
val lastName: String
val jobType: Int
}
data class EmployeeForm(
override var firstName: String = "",
override var lastName: String = "",
override var jobType: Int = 0
): Employee {
fun toEmployee(): Employee = this.copy()
fun copyEmployee(employee: Employee): Employee = this.copy(
firstName = firstName,
lastName = lastName,
jobType = jobType
)
}
但是,这意味着表单包含员工的所有字段,这可能是您不想要的
另外,我个人更喜欢您在开始时所做的,两次列出字段不会有问题,只需为您的函数编写测试,当您想要添加功能时,无论如何,您都将为该功能添加测试。您应该能够使用反射来执行此操作:检查员工
和员工表单
中的属性列表,通过匹配的名称调用构造函数(用于处理默认参数)。当然,缺点是,如果缺少任何属性,就不会出现编译时错误(但在这种情况下,任何测试都可能失败并告诉您该问题)
近似和未测试(不要忘记添加kotlin reflect
依赖项):
inlinefun复制(x:Any):T{
val construct=T::class.primaryConstructor
val props=x::class.memberProperties.associate{
//假设x上的所有属性都是构造函数的有效参数
配对(construct.findParameterByName(it.name)!!,
它。呼叫(x))
}
返回construct.callBy(props)
}
//以雇员的形式
fun toEmployee()=复制(此)
您可以使用Scala宏在编译时进行检查,但我认为在Kotlin中不可能做到这一点。您应该能够使用反射:检查Employee
和EmployeeForm
中的属性列表,通过匹配的名称调用构造函数(用于处理默认参数)。当然,缺点是,如果缺少任何属性,就不会出现编译时错误(但在这种情况下,任何测试都可能失败并告诉您该问题)
近似和未测试(不要忘记添加kotlin reflect
依赖项):
inlinefun复制(x:Any):T{
val construct=T::class.primaryConstructor
val props=x::class.memberProperties.associate{
//假设x上的所有属性都是构造函数的有效参数
配对(construct.findParameterByName(it.name)!!,
它。呼叫(x))
}
返回construct.callBy(props)
}
//以雇员的形式
fun toEmployee()=复制(此)
您可以使用Scala宏进行编译时检查,但我认为在Kotlin中是不可能的。您所说的可重用是什么意思?您希望如何重复使用它?你能举个例子吗?我现在不明白你的