假设这些接口为
interface RatingValue {
val value: Int
}
interface RatingValues {
fun ratings() : List<Int>
fun cumulativeRating() : Int = ratings().sum()
}
还有一堆类似于的枚举
enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues {
override fun ratings() = values().map(MarkFoo::value)
}
}
有没有一种方法可以将ratings((函数的实现一般提取到RatingValues接口中,以避免在所有枚举的伴随中有基本相同的精确实现?每个枚举都将实现RatingValue,每个枚举都有一个实现RatingValues 的同伴
您需要生成RatingValues
接口才能从中访问Enum<T>
和RatingValue
的方法。但是,由于实体化泛型不允许用于接口,甚至不允许用于其虚拟成员,因此您必须将这些方法转换为扩展:
interface RatingValues<T>
inline fun <reified T> RatingValues<T>.ratings(): List<Int> where T : RatingValue, T : Enum<T> = enumValues<T>().map { it.value }
inline fun <reified T> RatingValues<T>.cumulativeRating(): Int where T : RatingValue, T : Enum<T> = ratings().sum()
用法:
enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues<MarkFoo>
}
问题是,这些方法不能同时声明为抽象接口成员,因为在这种情况下,扩展将被隐藏。因此,它们现在只能在该接口上调用特定的T
(枚举,实现RatingValue
接口(,并且不能被覆盖。对于其他类型,接口将是空的,没有任何方法可以覆盖:
class X(override val value: Int) : RatingValue
class XX : RatingValues<X> {
override fun ratings(): List<Int> { /*...*/ } //Impossible now
override fun cumulativeRating(): Int { /*...*/ } //Impossible now
}
val res = XX.ratings() // Will not compile now since X is not enum
如果您也打算以上述方式使用此接口,那么您必须像以前一样声明接口,只添加一个扩展名,但名称不同(如ratingsForEnums
(,并在每次为enums:实现此接口时添加一些样板文件
interface RatingValues<T> {
fun ratings(): List<Int>
fun cumulativeRating(): Int = ratings().sum()
}
inline fun <reified T> RatingValues<T>.ratingsForEnums(): List<Int> where T : RatingValue, T : Enum<T> = enumValues<T>().map { it.value }
enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues<MarkFoo> {
override fun ratings() = ratingsForEnums()
}
}
如果您将只使用这个接口与枚举进行对比,那么在接口级别上明确地对T
施加限制也是有意义的:
interface RatingValues<T> where T : RatingValue, T : Enum<T>