Может ли абстрактный класс работать после инициализации дочернего класса? - PullRequest
0 голосов
/ 28 октября 2019

Классы, которые я использую, являются более сложными, чем этот, но я думаю, что этот произвольный пример будет работать так же хорошо. Допустим, у меня есть базовый абстрактный класс, который всегда хочет умножить одного из его членов Int, foo, на 2. На самом деле все равно, какое значение, если это Int. Также, скажем, нам все равно, когда произойдет это умножение, если оно происходит во время конструктора. Наконец, foo не может быть передан как параметр конструктора. Это должен быть член класса, переопределенный дочерним классом.

abstract class ExampleClass {
    abstract val foo: Int
    init {
        println("Here is foo times 2!: ${foo * 2}")
    }
}

class ChildClass : ExampleClass() {
    override val foo = 5
}

Это не сработает, очевидно. Родительские классы создаются в первую очередь, поэтому во время выполнения выдается ошибка, поскольку элемент еще не будет создан. Но в моих условиях я не против, если работа с foo произойдет после того, как будет создан экземпляр дочернего класса. Есть ли способ для родительского класса сказать: «Сделай это, как только мой ребенок закончит инстанцировать»? Или мне просто нужно уступить компромиссу:

abstract class ExampleClass {
    abstract val foo: Int
    fun bar() {
        println("Here is foo times 2!: ${foo * 2}")
    }
}

class ChildClass : ExampleClass() {
    override val foo = 5
    init {
       bar()
    }
}

И иметь всемои дочерние классы вызывают bar() на init? Это неправильно, потому что работа с foo будет выполняться только один раз.

Ответы [ 2 ]

2 голосов
/ 28 октября 2019

Я полагаю, что ответ отрицательный, это невозможно.

Язык котлина Документация по инициализации класса гласит:

[B]• во время выполнения конструктора базового класса свойства, объявленные или переопределенные в производном классе, еще не инициализированы. Если любое из этих свойств используется в логике инициализации базового класса (прямо или косвенно, через другую переопределенную реализацию открытого члена), это может привести к некорректному поведению или сбою во время выполнения. Поэтому при проектировании базового класса следует избегать использования открытых членов в конструкторах, инициализаторах свойств и блоках инициализации.

Свойство abstract присуще open, поэтому рекомендация здесь применима ка также ваш случай: спроектируйте свои классы, чтобы избежать этого.

Кроме того, я не могу найти какой-либо метод в стиле обратного вызова или какой-либо другой способ "подключиться" к логике / потоку инициализации класса и сказать "сделать"foo() после завершения инициализации ".

0 голосов
/ 28 октября 2019

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

abstract class ExampleClass {
    abstract val foo: Int
    init {
        println("Here is foo times 2!: ${foo * 2}")
    }
}

class ChildClass : ExampleClass() {
    override val foo
    get() = 5
}

fun main() {
    val test = ChildClass()
}

Попробуйте здесь и с изменяемым здесь

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