我有多个data class
字段,这些字段在表单中使用,如果已填充任何字段,则需要它们返回true
方法。
我不想为所有类重写这个,所以我现在这样做:
data class Order(var consumer: String, var pdfs: List<URI>): Form {
override val isEmpty(): Boolean
get() = checkEmpty(consumer, pdfs)
}
data class SomethingElse(var str: String, var set: Set<String>): Form {
override val isEmpty(): Boolean
get() = checkEmpty(str, set)
}
interface Form {
val isEmpty: Boolean
fun <T> checkEmpty(vararg fields: T): Boolean {
for (f in fields) {
when (f) {
is Collection<*> -> if (!f.isEmpty()) return false
is CharSequence -> if (!f.isBlank()) return false
}
}
return true;
}
}
这显然不是很漂亮也不是类型安全的。
在不将每个属性抽象为某种Field
类型的情况下,有什么更惯用的方法呢?
澄清:我正在寻找的是一种详尽无遗的方法when
,例如提供所有允许的类型(String
,Int
,List
,Set
)以及每个人的功能,告诉他们是否为空。就像带有方法isEmptyFormField
的“扩展接口”一样。
答案 0 :(得分:3)
有点hacky但应该工作。
每个data class
每个构造函数参数创建一组方法。它们被称为componentN()
(其中N
是从1
开始的数字,表示构造函数参数)。
您可以在界面中放置此类方法,并使data class
隐式实现它们。见下面的例子:
data class Order(var consumer: String, var pdfs: List) : Form
data class SomethingElse(var str: String, var set: Set) : Form
interface Form {
val isEmpty: Boolean
get() = checkEmpty(component1(), component2())
fun checkEmpty(vararg fields: T): Boolean {
for (f in fields) {
when (f) {
is Collection -> if (!f.isEmpty()) return false
is CharSequence -> if (!f.isBlank()) return false
}
}
return true;
}
fun component1(): Any? = null
fun component2(): Any? = null
}
您还可以添加fun component3(): Any? = null
等...以处理data class
中包含2个以上字段的案例(例如NullObject
模式或直接在null
处理checkEmpty()
{1}}方法。
正如我所说,它有点像hacky但也许会对你有用。
答案 1 :(得分:2)
如果你要做的就是检查isEmpty
/ isBlank
/ isZero
/等。那么你可能不需要通用的checkEmpty
函数等:
data class Order(var consumer: String, var pdfs: List<URI>) : Form {
override val isEmpty: Boolean
get() = consumer.isEmpty() && pdfs.isEmpty()
}
data class SomethingElse(var str: String, var set: Set<String>) : Form {
override val isEmpty: Boolean
get() = str.isEmpty() && set.isEmpty()
}
interface Form {
val isEmpty: Boolean
}
然而,如果你实际上做了一些更复杂的事情,那么根据你补充的澄清,我相信“将每个属性抽象成某种Field
- 类型”正是你想要的就是不要做每个Field
的{{1}}个实例部分,但在需要时创建它们的列表:
data class
这样可以在不更改data class Order(var consumer: String, var pdfs: List<URI>) : Form {
override val fields: List<Field<*>>
get() = listOf(consumer.toField(), pdfs.toField())
}
data class SomethingElse(var str: String, var set: Set<String>) : Form {
override val fields: List<Field<*>>
get() = listOf(str.toField(), set.toField())
}
interface Form {
val isEmpty: Boolean
get() = fields.all(Field<*>::isEmpty)
val fields: List<Field<*>>
}
fun String.toField(): Field<String> = StringField(this)
fun <C : Collection<*>> C.toField(): Field<C> = CollectionField(this)
interface Field<out T> {
val value: T
val isEmpty: Boolean
}
data class StringField(override val value: String) : Field<String> {
override val isEmpty: Boolean
get() = value.isEmpty()
}
data class CollectionField<out C : Collection<*>>(override val value: C) : Field<C> {
override val isEmpty: Boolean
get() = value.isEmpty()
}
组件等的情况下为您提供类型安全性,并且可以让您“彻底data class
”。
答案 2 :(得分:1)
您可以使用null
表示“未指定”:
data class Order(var consumer: String?, var pdfs: List<URI>?) : Form {
override val isEmpty: Boolean
get() = checkEmpty(consumer, pdfs)
}
data class SomethingElse(var str: String?, var set: Set<String>?) : Form {
override val isEmpty: Boolean
get() = checkEmpty(str, set)
}
interface Form {
val isEmpty: Boolean
fun <T> checkEmpty(vararg fields: T): Boolean = fields.all { field -> field == null }
}
这里的想法与Java中Optional<T>
的想法相同,但没有额外的对象等。
你现在不得不担心null safety但是如果你的字段意图有缺席/空的概念那么这似乎是合适的(UsingAndAvoidingNullExplained · google/guava Wiki)。