联盟类型/扩展接口

时间:2016-08-18 17:13:13

标签: oop interface kotlin

我有多个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,例如提供所有允许的类型(StringIntListSet)以及每个人的功能,告诉他们是否为空。就像带有方法isEmptyFormField的“扩展接口”一样。

3 个答案:

答案 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)。