使用接口和类在Kotlin中进行类型检查

使用接口和类在Kotlin中进行类型检查,kotlin,Kotlin,我有一个名为可识别的接口 interface Identifiable { var id: String` } 我有几个类遵循这个接口。比如说 class ArticleShrinked(val category: ArticleCategory, override var id: String, val timestamp: Date) : Shrinkable, Identifiable, In

我有一个名为可识别的接口

interface Identifiable {
    var id: String`
}
我有几个类遵循这个接口。比如说

class ArticleShrinked(val category: ArticleCategory,
                      override var id: String,
                      val timestamp: Date) : Shrinkable, Identifiable, Indexable {

    override val order: String
        get() = "id"
}
我有一个函数,它接受一个对象,该对象确认可识别并检测其类,并根据类进行操作

// There has to be a bettwe way to deal with this
fun setItem(item: Identifiable?) {
        val article: Article? = item as? Article
        if (article != null) {
            // do something with article
        }

        val shrinked: ArticleShrinked? = item as? ArticleShrinked
        if (shrinked != null) {
            // do something with shrinked
        }

        val bloated: ArticleBloated? = item as? ArticleBloated
        if (bloated != null) {
            // do something with bloated
        }

        val annotation: ArticleAnnotation? = item as? ArticleAnnotation
        if (annotation != null) {
            // do something with bloated
        }
}
在这里,按常规方式进行打字检查不起作用

if (item is Article)
把它放在switch语句中也会失败

when (item) {

   is Article -> // do something

}
甚至使用
项作为任何?as文章
不起作用。知道如何更优雅地编写函数吗?

在Kotlin(和Java)中,仅仅实现与接口中具有相同签名的方法是不够的;为了以编译器认可的方式实现接口,您必须在定义类时明确指定接口。只有这样,您才能实现正确的方法,并且只有这样类型系统才能识别关系

因此,
is
检查不会询问“此对象是否实现了正确的方法?”它会询问“此对象是否从类型层次结构中的正确接口下降?”

在这种情况下,
ArticleShrinked
实现接口
可收缩的
可识别的
,和
可索引的
,但它不实现
文章
。因此它不是
文章
的子类型,
ArticleShrinked
对象不是
文章
,即使它看起来像一个


这可能会有很大的限制(特别是如果你想要你没有编写的类来实现你的接口,这是不可能的)。但是这样更安全。否则,你可能会发现你自己的类错误地实现了各种接口,只是因为您碰巧选择了相同的方法名。

一种方法可能是去掉接口并使用抽象类,以便在运行时执行类型检查。但是,您需要在
可收缩
可索引
可识别
之间使用继承。然后expect我希望使用泛型作为
setItem
函数的参数

比如:

可识别的抽象类(valid:String)
抽象类可索引(id:String,val-index:Int):可识别(id)
抽象类可收缩(id:String,index:Int,val-shrink:Boolean):可索引(id,index)
类ArticleShrinked(id:String,index:Int,shrink:Boolean):可收缩(id,index,shrink)
类ArticleBloated()
类ArticleAnnotation()
//必须有一个更好的方法来处理这个问题
趣味套装项目(项目:有吗?){
项目?让我们{
何时(项目){
是ArticleAnnotation->{
}
文章是否臃肿->{
}
文章是否缩小->{
}
其他->{
}
}
}?:运行{
//是空的
}
}

似乎您需要一个抽象类而不是接口这似乎是密封类的一个很好的用例我不明白为什么
when
语句不起作用。正如你所描述的,它是如何失败的?通常,当您发现自己在检查类的类型以决定如何反应时,会产生代码气味,您应该在超级类型中放置一个方法,以便每个实现都可以描述自己的行为。但有时这是不切实际的,就像这个类正在对其他项做一些事情一样。如果是这样的话,密封类将是首选。完美的解释,谢谢!我猜“is”不合适,因为“instance of”只在类上工作,而不在接口上,对吗?@NicolaGallazzi
is
就像Java的
instanceof
:它检查对象的类型。  因此,它可以根据任何类型检查对象:可以是一个简单的类名,例如
String
;从它派生的类型,例如
String?
List
*;接口,如
CharSequence
;或者从中派生的类型,例如
CharSequence?
。  试试看!  (*注意,如果一个类被参数化,那么空的类名不是一个类型,因此
List
不起作用。  但是,由于类型擦除,无法检查特定的类型参数;只能使用通配符。)