56 votes

Extension d'une classe de données à partir d'une classe scellée en Kotlin

J'ai un ensemble de classes de données qui partagent certains champs communs. Idéalement, j'aimerais les déclarer dans un super-type (Message dans cet exemple), et pouvoir écrire des fonctions qui opèrent sur le super-type si elles ont besoin d'accéder à ces champs communs (messageId dans cet exemple).

fun operate(m: Message) {
  use(m.messageId)
}

J'ai essayé d'y parvenir en étendant mes classes de données à partir d'une classe scellée.

Les classes de données peuvent étendre les classes scellées, mais je ne suis pas sûr qu'elles puissent accepter les arguments requis par la classe scellée "supertype".

  1. L'extension d'une classe ordinaire à partir d'une classe scellée se compile très bien.

    sealed class Message(val messageId: String)
    
    class Track(val event: String, messageId: String): Message(messageId)
  2. Cependant, le changer en une classe de données ne compile pas ("Le constructeur primaire de la classe de données ne doit avoir que des paramètres de propriété (val/var)").

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, messageId: String): Message(messageId)
  3. Déclarer le paramètre en tant que propriété ne compile pas non plus ("'messageId' hides member of supertype 'Message' and needs 'override' modifier'").

    sealed class Message(val messageId: String)
    
    data class Track(val event: String, val messageId: String): Message(messageId)
  4. Ouvrir la propriété supertype et la surcharger dans chacune des classes de base compile bien :

    sealed class Message(open val messageId: String)
    
    data class Track(val event: String, override val messageId: String): Message(messageId)

Idéalement, j'aimerais quelque chose de proche de l'option 2 - cela me permet de combiner le meilleur des deux mondes.

Sinon, il me semble que mes options sont soit d'élaborer à la main mes propres fonctionnalités de classe de données (copie, code de hachage, égaux, etc.) avec l'option 1, soit de vivre avec un compromis en ouvrant les propriétés des super-types avec l'option 4.

93voto

Kiskae Points 11240

Les options 3 et 4 auraient pour conséquence que la classe détiendrait messageId deux fois. Une fois dans la nouvelle classe et une fois dans sa superclasse.

La solution consiste à déclarer mais pas à définir la variable dans la superclasse :

sealed class Message {
    abstract val messageId: String
}

data class Track(val event: String, override val messageId: String): Message()

Cela rendra le messageId disponible sur Message mais délègue le stockage à ce qui l'implémente.

0 votes

Les classes de données étendues doivent-elles être imbriquées dans une superclasse scellée ou simplement dans le même fichier ? kotlinlang.org/docs/tutorials/kotlin-for-py/

0 votes

@alvaro Cela semble être le cas, il semble que seules les restrictions normales de la classe scellée s'appliquent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X