Котлина супер не называйте

У меня есть класс, расширяющий другой, но в этом классе я не хочу вызывать суперконструктор. Как я могу это решить?

Вот фрагмент моего кода

class SubarticlePagerAdapter(fragmentManager: FragmentManager, context: Context, var selectedArticleName: String) : ArticlePagerAdapter(fragmentManager, context) {

    var subarticleDao: ArticleDao
    var itemCount = 0

    init {
        ApplicationHelper().getApplication(context).appComponent.inject(this)
        subarticleDao = ApplicationHelper().getApplication(context).subarticleDaoSession.articleDao
        initBundles(context)
    }

    override fun initBundles(context: Context?) {
        }
    }

Моя проблема, когда этот конструктор вызывается, сначала запускается конструктор родительского класса, и оттуда будет вызываться initBundles (), но в это время subarticleDao и selectedArticleName не установлены, и я получаю исключение.

Я могу думать о двух способах - вы можете создать вторичный конструктор, который не выполняет никакой выборки Dao и Name, или добавить дополнительный логический параметр в ArticlePagerAdapter, и если логическое значение false, не входите в Dao и Name.

Sreeram Sunkara 26.06.2018 16:44
2
1
954
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

TL; DR

Я бы посоветовал вам переместить код из блока init в функцию initBundles и использовать там свои переменные после инициализации. Тогда не было бы необходимости избегать вызова конструктора суперклассов.

Подробный ответ

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

То, что вы сделали со своим кодом (переопределение - возможно, абстрактного - метода, initBundles из вашего суперкласса - это в значительной степени шаблон метода шаблон. Поэтому мне кажется, что цель initBundles - позволить подклассам настраивать части инициализации ... вы делаете в своем блоке инициализации.

РЕДАКТИРОВАТЬ: как Пол указал в комментариях, вы не можете использовать член selectedArticleName до завершения инициализации ваших базовых классов. Таким образом, если базовый класс вызывает initBundles во время своей инициализации, то свойства в подклассе не будут инициализированы, как также указано в Ссылка Павла.

Поскольку в этом фрагменте вы не используете selectedArticleName, вы можете просто переместить свои данные для инициализации в функцию initBundles и инициализировать там свой subarticleDao.

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

Хотя я полностью согласен с вашим подходом, вы упустили одну деталь. selectedArticleName (или, скорее, его значение) нельзя использовать в initBundles, если он вызывается из конструктора или блока инициализации родительского класса. Это один из редких случаев, когда котлин небезопасен для null (см. здесь).

Paul Georg Podlech 27.06.2018 09:40

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

LPeteR90 28.06.2018 14:11

Помимо вариантов дизайна, этот ответ на самом деле не отвечает на исходный вопрос. Вообще.

aholt 05.07.2018 19:29

ну, к сожалению, в какой-то мере вы правы. это из-за правок, которые мне пришлось внести (см. другие комментарии). Однако я думаю, что я предложил действительную альтернативу предоставленному коду (переместить блок init в initBundles). Кроме того, я бы не хотел поощрять попытки избежать вызова суперконструктора в Kotlin, похоже, это не предусмотрено дизайном языка.

LPeteR90 06.07.2018 21:07

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