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

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

在程序的开发中,我使用数据类来表示播放列表。 在设计中的一个点上,我想有一个特殊types的Playlist EmptyPlaylist

我无法得到这个工作。

你将如何实现与Kotlin的这种关系?

在Java中,我只是扩展Playlist (或者可能为它们创建一个接口/抽象类来inheritance)。

我只是希望能够有一个List而不是List

最后,我创建了一个Playlist对象,但是我感兴趣的是可以创建带有数据类的IS-A层次结构。

UPD:Kotlin Beta增加了对data类的限制,所以答案也被更新了。

  • 数据类不能是抽象的,开放的,封闭的或内在的;
  • 数据类不能扩展其他类(但可能实现接口)。

所以构建层次结构的唯一选择是接口。 未来版本中可能会发布此限制。


Playlist中inheritanceEmptyPlaylist这个根据你的文字推测为非空的想法看起来有点矛盾,但是有一些选择:

  • 您可以使TracksPlaylistEmptyPlaylist实现一些Playlist界面。 这是合理的,因为EmptyPlaylist可能不包含Playlist所做的所有事情。 这看起来像:

     public interface Playlist data class TracksPlaylist(val name: String, val tracks: List) : Playlist data class EmptyPlaylist(val name: String): Playlist 
  • 如果你不希望EmptyPlaylist多个实例存在,你可以使它成为一个val而不是独立的类,并避免is-checks,只是比较

     val EMPTY_PLAYLIST = TracksPlaylist("EMPTY", listOf()) 

    空的播放列表全部相等时,这是适用的,以便单个对象足以代表它们全部。

  • 你可以使用sealed类 。 这不允许你使用data类,但是sealed类可能适合构建这样的类层次结构。

    sealed类是一个抽象类,只能在其内部声明它的子类。 这给了编译器保证这些是唯一的子类。 例:

     sealed class Playlist(val name: String) { class Tracks(name: String, val tracks: List): Playlist(name) class Playlists(name: String, val innerPlaylists: List): Playlist(name) object Empty: Playlist("EMPTY") } 

    之后, when声明了密封类的所有子类和对象,那么您将能够使用when语句而不指定else分支:

     when (p) { is Playlist.Tracks -> { /* ... */ } is Playlist.Playlists -> { /* ... */ } Playlist.Empty -> { /* ... */ } } 

    但是,这个选项需要你自己处理equalshashCodetoStringcopycomponentN ,如果你需要的话。