我有DTO对象,然后我需要对对象集合进行动态排序,有点像数据库ORDER BY,但是我没有数据库来实际使查询完成实际工作(我知道,但是我今天有什么...)。
在我看来,StatusComparator和TypeComparator应该可以完全通用地重写,并且还可以利用反射,这样我就不需要为API中的每个对象编写一个(我还有三个)这项服务,而且确实变得越来越重复)。
一旦我了解编写此代码的正确方法,我计划将Comparators提取到自己的库中,以便与公司中的其他部门共享该模式,以使他们的代码更易于编写。
这段代码在Kotlin中,因此,我们真的想尽可能地专注于该实现。
DTO:
$(document).ready(function() {
$('.model_link').click(function() {
var buttonName = $(this).attr('id').split('_')[0];
$('#button').val(buttonName);
$('form').submit();
});
});
比较:
@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
}
}
}
}
我现在在我的问题中也看到,我也许也可以将这种模式应用于我的实际服务,但是让我们一次迈出这一步。
答案 0 :(得分:1)
@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
使用反射按名称查找属性,然后提取属性的吸气剂作为Conparable
的选择器
然后根据asc
参数,使用标准函数compareBy
and compareByDescending
将getter
转换为通用类型的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)
}
用法类似于本例中的主要功能。通过KClass
访问::
对象。
然后,调用第一个扩展函数并使用第二个扩展函数来组合Comparable
: