gpt4 book ai didi

java - 如何使用泛型和反射来减少代码

转载 作者:行者123 更新时间:2023-12-02 10:16:02 25 4
gpt4 key购买 nike

我有 DTO 对象,然后我需要动态对对象集合进行排序,有点像数据库 ORDER BY,但我没有数据库来实际使查询完成实际工作(我知道,但它是我今天有什么...)。

在我看来,StatusComparator 和 TypeComparator 应该能够被重写为完全通用的,并且可能还利用反射,这样我就不需要为 API 中的每个对象编写一个(我还有三个)对于这项服务,它变得非常重复)。

一旦我理解了编写此代码的正确方法,我计划将比较器提取到他们自己的库中,以便我可以与公司的其他部门共享该模式,以使他们的代码更易于编写。

这段代码是用 Kotlin 编写的,所以我真的希望尽可能地关注该实现。

DTO:

@Table("type")
data class TypeObject(

@get:NotNull
@PrimaryKey
@JsonProperty("id") val id: String,

@get:NotNull
@Column("type")
@JsonProperty("type") val type: String,

@Column("is_deleted")
@JsonProperty("isDeleted") val isDeleted: Boolean? = null
)

@Table("status")
data class StatusObject(
@get:NotNull
@PrimaryKey
@JsonProperty("id") val id: String,

@get:NotNull
@JsonProperty("status") val status: String,

@Column("is_deleted")
@JsonProperty("isDeleted") val isDeleted: Boolean? = null
)

比较:

@Component
class StatusComparator<T : StatusObject> {
fun buildComparator(
field: String,
asc: Boolean
): Comparator<T> {
return if (asc) {
compareBy {
getField(field, it)
}
} else {
compareByDescending {
getField(field, it)
}
}
}

private fun getField(
field: String,
it: StatusObject
): Comparable<*>? {
return when (field.toLowerCase()) {
"id" -> it.id
"status" -> it.status
else -> it.isDeleted
}
}
}

@Component
class TypeComparator<T : TypeObject> {
fun buildComparator(
field: String,
asc: Boolean
): Comparator<T> {
return if (asc) {
compareBy {
getField(field, it)
}
} else {
compareByDescending {
getField(field, it)
}
}
}

private fun getField(
field: String,
it: TypeObject
): Comparable<*>? {
return when (field.toLowerCase()) {
"id" -> it.id
"type" -> it.type
else -> it.isDeleted
}
}
}

我的类型服务中的示例用法:

@Service
class TypeApiServiceImpl(
private val repo: TypeRepository,
private val sortListBuilder: SortListBuilder,
private val customComparator: TypeComparator<TypeObject>
) : TypeApiService {

override fun get(
sort: String,
filterId: UUID,
filterType: String,
filterIsDeleted: Boolean
): Mono<DocumentTierModels> {
return if (filterId != UUID.fromString("00000000-0000-0000-0000-000000000000")) {
this.getTypeById(filterId)
} else {
val objects = this.getTypeByFilter(filterType, filterIsDeleted)

if (sort != "null") {
this.getSortedTypes(sort, objects)
} else {
TypesModels(objects, MetaModel(null, listOf())).toMono()
}
}
}

private fun sortObject(
objects: List<TypeObject>,
sortItems: List<String>
): List<TypeObject> {
when (sortItems.count()) {
1 -> {
val fieldAndDirection1 = sortItems[0].split(',')

return objects
.sortedWith(customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc"))
}
2 -> {
val fieldAndDirection1 = sortItems[0].split(',')
val fieldAndDirection2 = sortItems[1].split(',')

return objects
.sortedWith(
customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc")
.then(customComparator.buildComparator(fieldAndDirection2[0], fieldAndDirection2[1] == "asc"))
)
}
3 -> {
val fieldAndDirection1 = sortItems[0].split(',')
val fieldAndDirection2 = sortItems[1].split(',')
val fieldAndDirection3 = sortItems[2].split(',')

return objects
.sortedWith(
customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc")
.then(customComparator.buildComparator(fieldAndDirection2[0], fieldAndDirection2[1] == "asc"))
.then(customComparator.buildComparator(fieldAndDirection3[0], fieldAndDirection3[1] == "asc"))
)
}
else -> {
return objects
}
}
}
}

我的状态服务中的示例用法:

@Service
class StatusesApiServiceImpl(
private val repo: StatusRepository,
private val sortListBuilder: SortListBuilder,
private val customComparator: StatusComparator<StatusObject>
) : StatusesApiService {

override fun get(
sort: String,
filterId: UUID,
filterStatus: String,
filterIsDeleted: Boolean
): Mono<StatusModels> {
return if (filterId != UUID.fromString("00000000-0000-0000-0000-000000000000")) {
this.getStatusById(filterId)
} else {
val objects = this.getStatusByFilter(filterStatus, filterIsDeleted)

if (sort != "null") {
this.getSortedStatuses(sort, objects)
} else {
StatusModels(objects, MetaModel(null, listOf())).toMono()
}
}
}

private fun getSortedStatuses(
sort: String,
objects: List<StatusObject>
): Mono<StatusModels> {
var objects1 = objects
var sortList: MutableList<String> = mutableListOf()
val sortItems = sortListBuilder.getSortItems(sort)

if (sortItems != null) {
sortList = sortListBuilder.buildSortList(sortItems)
objects1 = this.sortObject(objects1, sortItems)
}

val meta = MetaModel(null, sortList)

return StatusModels(objects1, meta).toMono()
}

private fun sortObject(
objects: List<StatusObject>,
sortItems: List<String>
): List<StatusObject> {
when (sortItems.count()) {
1 -> {
val fieldAndDirection1 = sortItems[0].split(',')

return objects
.sortedWith(customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc"))
}
2 -> {

val fieldAndDirection1 = sortItems[0].split(',')
val fieldAndDirection2 = sortItems[1].split(',')

return objects
.sortedWith(customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc")
.then(customComparator.buildComparator(fieldAndDirection2[0], fieldAndDirection2[1] == "asc")))
}
3 -> {
val fieldAndDirection1 = sortItems[0].split(',')
val fieldAndDirection2 = sortItems[1].split(',')
val fieldAndDirection3 = sortItems[2].split(',')

return objects
.sortedWith(customComparator.buildComparator(fieldAndDirection1[0], fieldAndDirection1[1] == "asc")
.then(customComparator.buildComparator(fieldAndDirection2[0], fieldAndDirection2[1] == "asc"))
.then(customComparator.buildComparator(fieldAndDirection3[0], fieldAndDirection3[1] == "asc")))
}
else -> {
return objects
}
}
}
}

我现在还在问题中看到,我也可以将这种模式应用到我的实际服务中,但让我们一次迈出一步。

最佳答案

反射(reflection)

@Suppress("UNCHECKED_CAST")
fun <T : Any> KClass<T>.compareByProperty(propName: String, asc: Boolean = true): Comparator<T> {
val property = declaredMemberProperties.first { it.name == propName }
val getter = property::get as (T) -> Comparable<*>

if (asc) {
return compareBy(getter)
}
return compareByDescending(getter)
}

第一个扩展函数compareByProperty使用反射按名称查找属性,然后提取属性的getter作为Conparable的选择器

然后根据 asc 参数,getter 被转换为具有标准函数 compareBy and compareByDescending 的泛型类型的 Comparator :

组合助手

inline fun <reified T : Any> Comparator<T>.thenByProperty(propName: String, asc: Boolean = true) =
then(T::class.compareByProperty(propName, asc))

第二个扩展函数允许组合Comparator:

用法

fun main() {
val typeObjects = listOf(...)
val comparator = TypeObject::class.compareByProperty("id")
.thenByProperty("type", asc = false)

val sortedTypes = typeObjects.sortedWith(comparator)
}

用法类似于本示例中的 main 函数。通过:: 访问KClass 对象。然后调用第一个扩展函数并使用第二个扩展函数来组合Comparable:

关于java - 如何使用泛型和反射来减少代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54677565/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com