Инициализация сопутствующего объекта после внутренних объектов

Допустим, я хочу создать закрытый класс, заполненный некоторыми объектами. Затем я хочу создать список всех таких объектов, поэтому я создаю список в объекте-компаньоне:

fun main() {
    println(Color.Blue)
    println(Color.allColors)
}

sealed class Color {
    object Red : Color();
    object Blue : Color();

    companion object {
        val allColors = listOf(
                Red,
                Blue
        )
    }
}

Однако проблема с приведенным выше кодом заключается в том, что при вызове Color.Blue непосредственно в первый раз, объект-компаньон инициализируется перед Blue и, следовательно, результирующий список содержит [Red, null], Это вдвойне проблематично, поскольку Котлин предполагает, что список содержит ненулевые значения.

Я знаю, что приведенный выше пример достаточно прост, чтобы я мог заменить sealed class с enum, но это всего лишь упрощенный пример. Во многих случаях полезно использовать запечатанные классы над перечислениями (например, когда вам нужно добавить параметры типа для отдельных объектов).

Как лучше всего решить эту проблему с наименьшим количеством шаблонов и распределением объектов? Я придумал два обходных пути, но мне не нравится ни один из них:

ленивый

fun main() {
    println(Color.Blue)
    println(Color.allColors)
}

sealed class Color {
    object Red : Color();
    object Blue : Color();

    companion object {
        val allColors by lazy {
            listOf(
                    Red,
                    Blue
            )
        }
    }
}

Вышеупомянутое решение выглядит хорошо и не вызывает большого количества котельной плиты, но оно создает один дополнительный объект, который живет вечно для каждого свойства в объекте-компаньоне. Я также должен был бы повторить ленивое ключевое слово на любых дополнительных свойствах.

Перемещение инициализации в другой объект

fun main() {
    println(Color.Blue)
    println(Color.allColors)
}

sealed class Color {
    object Red : Color();
    object Blue : Color();

    private object Initializer {
        val allColors = listOf(
                Red,
                Blue
        )
    }

    companion object {
        val allColors: List<Color>
            get() = Initializer.allColors
    }
}

Преимущество этого метода состоит в том, что он создает только один объект для всех свойств объекта-компаньона, но создает много дополнительных шаблонов.

Есть ли лучший способ добиться этого?

0 ответов

sealed class Color(var meh:Int) {
    object Red : Color(10)
    object Blue : Color(20)

    companion object {
        private var colorsList:List<Color>? = null
        val allColors:List<Color>
            get() = colorsList?:run{
                colorsList = listOf(
                        Red,
                        Blue
                )
                colorsList!!
            }
    }
}

Это синглтон всегда. Это просто еще один способ сделать это. Но объект Initializer выглядит чище.

Другие вопросы по тегам