Есть ли способ отложить инициализацию дорогостоящего поля в определенном конструкторе?

#kotlin #lazy-loading #lazy-initialization

#котлин #отложенная загрузка #ленивая инициализация

Вопрос:

У меня есть класс данных, который я хочу заполнить, где в одном конструкторе у меня уже есть данные, а в другом я хотел бы извлекать их только тогда, когда это требуется, что случается редко.

Пример кода будет выглядеть следующим образом:

 data class Source1(val str1: String)
data class Source2(val str2: String)

data class DTO(val data1: String, val data2: String) {
    // ctor which does not need laziness
    constructor(source1: Source1) : this(
        data1 = source1.str1,
        data2 = source1.str1
    )

    // ctor which needs costly data
    constructor(source2: Source2, costlyData: String) : this(
        data1 = source2.str2,
        data2 = costlyData
    )
}

fun demo() {
    val source1 = Source1("some str - 1")
    DTO(source1)

    val source2 = Source2("some str - 2")
    val costlyData: String = costlyOperation() // this is the operation I'd like to execute lazily
    DTO(source2, costlyData)
}

 

Комментарии:

1. kotlinlang.org/docs/reference/delegated-properties.html#lazy

Ответ №1:

Я бы сказал, что самым простым способом было бы принять функцию в качестве параметра конструктора, что-то вроде этого:

 class DTO(provider:()->String){
    constructor(data: String):this({data})

    val data by lazy{ provider()}
}
 

Таким образом, вы можете использовать его обоими способами:

 val eager = DTO("some str - 1")
val lazy = DTO(::costlyOperation)
 

Немного более приятный способ — иметь Source абстракцию с различными реализациями для предоставления постоянного значения и выполнения операции. Но общая идея была бы той же самой.

Хотя я бы больше не стал называть это DTO, и он теряет свои возможности класса данных в отношении содержимого.