如何模拟或实现Kotlin数据类的IS-A关系

如何模拟或实现Kotlin数据类的IS-A关系,kotlin,data-class,Kotlin,Data Class,我一直在探索Kotlin,并编写了一个小程序/脚本来完成一项我觉得很无聊的任务 在程序开发过程中,我使用数据类来表示播放列表。在设计过程中,我曾一度希望有一种特殊类型的播放列表,它是EmptyPlaylist 我没法让它工作 你将如何与Kotlin建立这种关系 在Java中,我只需要扩展Playlist,或者创建一个接口/抽象类,让它们从中继承 我只是想有一个列表,而不是列表 最后,我刚刚创建了一个Playlist对象,但我感兴趣的是,是否可以使用数据类创建is-a层次结构。UPD:Kotlin

我一直在探索Kotlin,并编写了一个小程序/脚本来完成一项我觉得很无聊的任务

在程序开发过程中,我使用数据类来表示播放列表。在设计过程中,我曾一度希望有一种特殊类型的播放列表,它是EmptyPlaylist

我没法让它工作

你将如何与Kotlin建立这种关系

在Java中,我只需要扩展Playlist,或者创建一个接口/抽象类,让它们从中继承

我只是想有一个列表,而不是列表


最后,我刚刚创建了一个Playlist对象,但我感兴趣的是,是否可以使用数据类创建is-a层次结构。

UPD:Kotlin Beta增加了对数据类的限制,因此答案也已更新

数据类不能是抽象的、开放的、密封的或内部的; 数据类不能扩展其他类,但可以实现接口。 因此,构建层次结构的唯一选项是接口。此限制可能在将来的版本中发布。 从播放列表继承EmptyPlaylist的想法看起来有点矛盾,根据您的文字,播放列表假定为非空,但有以下几种选择:

您可以使TracksPlaylist和EmptyPlaylist实现一些播放列表界面。这是合理的,因为EmptyPlaylist可能并不包含播放列表的所有功能。这看起来像:

public interface Playlist

data class TracksPlaylist(val name: String, val tracks: List<Track>) : Playlist
data class EmptyPlaylist(val name: String): Playlist
当空播放列表都相等时,此选项适用,因此单个对象足以表示所有播放列表

你可以用。这不允许您使用数据类,但密封类可能适合构建这样的类层次结构

密封类是一个抽象类,它只能在其主体内声明其子类。这使编译器保证这些是唯一的子类。例如:

sealed class Playlist(val name: String) {
    class Tracks(name: String, val tracks: List<Track>): Playlist(name)
    class Playlists(name: String, val innerPlaylists: List<Playlist>): Playlist(name)
    object Empty: Playlist("EMPTY")
}
但是,如果需要,此选项要求您自己处理equals、hashCode、toString、copy和componentN


谢谢我想我很困惑,因为网络的智慧表明扩展数据类是有问题的。我没有想过扩展一个抽象类,公平地说,我真是太笨了,我应该看到这个选项。在所有选项中,我喜欢最后一个!在字里行间,你可以像扩展普通类一样扩展数据类?是的,设计有点矛盾,因为它已经进化了;最初它只是处理一个播放列表文件和学习Kotlin。由于我更喜欢使用Kotlin,并且希望对脚本做更多的工作,所以它的功能有所增加,如果不是在代码行中。通常我不会从播放列表扩展EmptyPlaylist:@Gavin,是的,数据类继承是有限的:您不能在主构造函数中定义新属性,也不能重写componentN函数,您可能必须重写equals和hashCode,这是在父类和子类中处理类层次结构时另一个棘手的问题。但是,如果您只是在类主体中添加新的属性和函数,而不希望它们被隐藏在代码下的数据自动使用,那么这是可能的。谢谢您的澄清。我认为这对我的目的是有效的。更新了答案,使其符合Kotlin对数据类的限制。最好展示您在Java代码或类似代码方面的尝试,以备将来的问题。。。
sealed class Playlist(val name: String) {
    class Tracks(name: String, val tracks: List<Track>): Playlist(name)
    class Playlists(name: String, val innerPlaylists: List<Playlist>): Playlist(name)
    object Empty: Playlist("EMPTY")
}
when (p) {
    is Playlist.Tracks -> { /* ... */ }
    is Playlist.Playlists -> { /* ... */ }
    Playlist.Empty -> { /* ... */ }
}