У меня есть класс, расширяющий другой, но в этом классе я не хочу вызывать суперконструктор. Как я могу это решить?
Вот фрагмент моего кода
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 не установлены, и я получаю исключение.
Я бы посоветовал вам переместить код из блока init в функцию initBundles и использовать там свои переменные после инициализации. Тогда не было бы необходимости избегать вызова конструктора суперклассов.
Я думаю, вам следует подумать о том, что вы хотите сделать со своим дизайном. Работа с идиомами языка не очень часто является хорошей идеей или признаком хорошего дизайна - по крайней мере, когда ваш язык - котлин :)
То, что вы сделали со своим кодом (переопределение - возможно, абстрактного - метода, initBundles из вашего суперкласса - это в значительной степени шаблон метода шаблон. Поэтому мне кажется, что цель initBundles - позволить подклассам настраивать части инициализации ... вы делаете в своем блоке инициализации.
РЕДАКТИРОВАТЬ: как Пол указал в комментариях, вы не можете использовать член selectedArticleName до завершения инициализации ваших базовых классов. Таким образом, если базовый класс вызывает initBundles во время своей инициализации, то свойства в подклассе не будут инициализированы, как также указано в Ссылка Павла.
Поскольку в этом фрагменте вы не используете selectedArticleName, вы можете просто переместить свои данные для инициализации в функцию initBundles и инициализировать там свой subarticleDao.
Однако, если вы на этом этапе используете нужно для использования свойств ваших подклассов, я бы действительно посоветовал вам переосмыслить свой дизайн. Должно быть несколько способов решить эту проблему, но чтобы решить, что лучше всего соответствует вашим требованиям, потребуется более глубокое понимание намерений, которые вы имеете в своем дизайне.
Хотя я полностью согласен с вашим подходом, вы упустили одну деталь. selectedArticleName (или, скорее, его значение) нельзя использовать в initBundles, если он вызывается из конструктора или блока инициализации родительского класса. Это один из редких случаев, когда котлин небезопасен для null (см. здесь).
Вы меня здесь. Просто попробовал, и значение свойства, переданного в подкласс, действительно равно нулю во время инициализации конструктора. Я обновлю свой ответ.
Помимо вариантов дизайна, этот ответ на самом деле не отвечает на исходный вопрос. Вообще.
ну, к сожалению, в какой-то мере вы правы. это из-за правок, которые мне пришлось внести (см. другие комментарии). Однако я думаю, что я предложил действительную альтернативу предоставленному коду (переместить блок init в initBundles). Кроме того, я бы не хотел поощрять попытки избежать вызова суперконструктора в Kotlin, похоже, это не предусмотрено дизайном языка.
Я могу думать о двух способах - вы можете создать вторичный конструктор, который не выполняет никакой выборки Dao и Name, или добавить дополнительный логический параметр в ArticlePagerAdapter, и если логическое значение false, не входите в Dao и Name.