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

加文

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

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

我无法使它正常工作。

您将如何与Kotlin建立这种关系?

在Java中,我只是扩展Playlist(或者可能创建一个接口/抽象类,以便它们都可以继承)。

我只是想能够拥有一个List<Playlist>而不是List<Playlist?>

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

热键

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

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

因此,构建其层次结构的唯一选择是接口。此限制可能会在将来的版本中发布。


根据您的话,假定 EmptyPlaylist 从中 继承 Playlist 是非空的想法 看起来有点矛盾,但是有一些选择:

  • 您可以两者都实现TracksPlaylistEmptyPlaylist实现一些Playlist接口。这是合理的,因为EmptyPlaylist可能不包含a的所有内容Playlist看起来像:

    public interface Playlist
    
    data class TracksPlaylist(val name: String, val tracks: List<Track>) : Playlist
    data class EmptyPlaylist(val name: String): Playlist
    
  • 如果您不希望EmptyPlaylist甚至存在多个实例,则可以将其设置为val代替不同的类,并避免进行is-checks,只需将其与

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

    空的播放列表都相等时,这适用于单个对象足以代表所有播放列表的情况。

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

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

    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无需指定else分支就可以使用语句

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

    然而,这个选项需要你来处理equalshashCodetoStringcopycomponentN你自己,如果你需要他们。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章