Расширение класса данных из закрытого класса в Котлине
У меня есть набор классов данных, которые разделяют некоторые общие поля. Поэтому в идеале я хотел бы объявить те в супертипе (Message в этом примере) и иметь возможность писать функции, которые работают с супертипом, если им нужен доступ к этим общим полям (messageId в этом примере).
fun operate(m: Message) {
use(m.messageId)
}
Я попытался выполнить это, расширив классы данных из закрытого класса.
Классы данных могут распространять закрытые классы, но не я не уверен, как/если они могут принимать аргументы, требуемые закрытым классом супертипа.
-
Расширение обычного класса из закрытого класса компилируется просто отлично.
sealed class Message(val messageId: String)
class Track(val event: String, messageId: String): Message(messageId)
-
Однако его изменение в класс данных не компилируется ( "Основной конструктор класса данных должен иметь только параметры свойства (val/var)".).
sealed class Message(val messageId: String)
data class Track(val event: String, messageId: String): Message(messageId)
-
Объявление параметра как свойства также не компилируется ("'messageId' скрывает член супертипа 'Message' и нуждается в переопределении 'модификатора').
sealed class Message(val messageId: String)
data class Track(val event: String, val messageId: String): Message(messageId)
-
Открытие свойства супертипа и его переопределение в каждом из базовых классов компилируется отлично:
sealed class Message(open val messageId: String)
data class Track(val event: String, override val messageId: String): Message(messageId)
В идеале я хотел бы что-то близкое к Варианту 2 - он позволяет мне комбинировать лучшее из обоих миров.
В противном случае мне кажется, что мои параметры - либо переносить мои собственные функции класса данных (copy, hashcode, equals и т.д.) с помощью опции 1, либо жить с компромиссом, открыв свойства супертипа с опцией 4.
Ответы
Ответ 1
Варианты 3 и 4 приведут к тому, что класс удерживает messageId
дважды. Однажды в новом классе и один раз в своем суперклассе.
Решение состоит в объявлении, но не определении переменной в суперклассе:
sealed class Message {
abstract val messageId: String
}
data class Track(val event: String, override val messageId: String): Message()
Это сделает messageId доступным на Message
, но делегирует хранилище тем, что его реализует.