Переопределить геттеры в Котлине? - PullRequest
0 голосов
/ 11 ноября 2018

Итак, у меня есть абстрактный класс Composition, у которого есть два потомка: один - это трек, а другой - альбом (который является группой треков).

class Composition(val name: String, ...)
class Track(name: String): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name)

Пока все хорошо. Теперь у меня есть продолжительность, которая добавлена. Он абстрактен в композиции, поэтому я могу переопределить его у детей:

abstract class Composition(...){
    abstract fun getDuration(): Int
}

Теперь я могу добавить метод переопределения в дорожке, который принимает его в качестве параметра:

class Track(..., private val duration: Int): Composition(...){
    override fun getDuration() = duration
}

И, наконец, я делаю альбом, длительность которого равна сумме треков:

class Album(..., val tracks: List<Track>): Composition(...){
    override fun getDuration() = tracks.sumBy { it.getDuration() }
}

Он работает как задумано, но я не понимаю, почему я не могу просто использовать tracks.sumBy { it.duration }, поскольку в свойствах Kotlin есть не что иное, как геттеры и сеттеры (я имею в виду getDuration в Composition).

Мне кажется, что я что-то упускаю, потому что, если бы тот же код был написан на Java, я мог бы назвать composition.duration как свойство - так что я думаю, что Kotlin позволяет это делать из кода Java, но не из кода Котлина, что печально.

Другой пример:

Допустим, у меня есть класс с именем Artist, который написал несколько Composition s:

class Artist(
    val nom: String,
    private val _compositions: MutableList<Composition> = ArrayList()
) {

    // HERE (I wrote the extension method List<E>.toImmutableList)
    fun getCompositions() : List<Composition> = _compositions.toImmutableList()
}

Это стандарт в Java (предоставление неизменяемых версий коллекций через геттеры, поэтому они не модифицируются); Котлин не признает это, хотя:

val artist = Artist("Mozart")
artist.getCompositions() // Legal
artist.compositions      // Illegal

Я думал о том, чтобы сделать это собственностью, но: - Если я выберу тип List<E>, я могу переопределить метод получения для возврата неизменяемого списка, но я не могу использовать обычные методы (add ...), поскольку List является неизменным - Если я выберу тип MutableList<E>, я не смогу переопределить метод get для возврата ImmutableList (который является подклассом List, который я написал, и, очевидно, не является подклассом MutableList).

Есть вероятность, что я делаю что-то нелепое, хотя есть простое решение, но сейчас я не могу его найти.

В конце мой вопрос таков: почему написанные вручную геттеры не считаются свойствами при написании из Kotlin?

И, если я ошибаюсь, каков ожидаемый способ решения обоих этих шаблонов?

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

Если вы хотите использовать его как свойство, вы должны использовать Kotlin-way для переопределения геттера.
Например:

abstract class Composition(...){
    abstract val duration: Int
}

// You can use "override" in constructor
// val - is immutable property that has only getter so you can just 
// remove private modifier to make possible get it.
class Track(..., override val duration: Int): Composition(...){
    ...
}

class Album(..., val tracks: List<Track>): Composition(...) {
    override val duration: Int 
        get() = tracks.sumBy { it.duration }
}

Также возможен случай, когда вам нужно изменяемое свойство, которое можно изменить только внутри объекта. В этом случае вы можете объявить изменяемое свойство с помощью приватного сеттера:

class SomeClass(value: Int) {
    var value: Int = value
        private set
}

Подробнее в документации: https://kotlinlang.org/docs/reference/properties.html#getters-and-setters

0 голосов
/ 11 ноября 2018

Вы должны определить продолжительность как абстрактное свойство, а не как функцию абстракции (https://kotlinlang.org/docs/reference/properties.html#getters-and-setters):

abstract class Composition(val name: String) {
    abstract val duration: Int
}
class Track(name: String, override val duration: Int): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name) {
    override val duration: Int
        get() = tracks.sumBy { it.duration }
}

Преобразование getter / setter как свойства работает только для классов Java (https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...