Builder на Kotlin
Проблем особых нет. Единственное, попытался реализовать на котлине паттерн Builder, который мог бы быть доступен из Java привычными для него методами. Интересует правильность моей реализации и что можно все таки улучшить
whalemare
Минусы билдеров:
- Изменяемый объект. Можно несколько раз вызвать какой-нибудь setter/wither, отправив значения вникуда.
- Изначально поломанный объект. Можно создать объект из пустого билдера, уповая на умолчания: Builder().create().
- Временный объект. Жизнь билдера крайне коротка, всего через несколько строк его забирает сборщик мусора.
Билдеры возникают там, где прямой вызов конструктора был бы слишком громоздким. Толстые конструкторы появляются, когда объект знает слишком много. Например, создание SheetMenu выглядит так:
SheetMenu(
titleId = R.string.menuTitle, // кстати, не хватает @StringRes
title = null,
menu = R.menu.someMenu, // не хватает @MenuRes
layoutManager = LinearLayoutManager(context),
adapter = null,
click = MenuItem.OnMenuItemClickListener { toast("click!"); true },
autoCancel = true,
showIcons = true
)
Этот объект пытается всё самостоятельно контролировать. Из-за этого возникают нестыковки:
- title и titleId исключают друг друга, т. к. отвечают за одно и то же — я, например, обобщил это вот таким путём.
- Зачем menu по умолчанию равно нулю? Какой смысл в меню без меню?
- Параметр showIcons не имеет смысла и игнорируется, если передан адаптер. Лучше обязать клиента передавать адаптер и предоставить удобный API для этого.
Замечания, не касающиеся билдера непосредственно
- Все свойства изменяемые (var). Какой смысл, например, менять menu после того, как меню уже создано?
- MenuItem.OnMenuItemClickListener#onMenuItemClick возвращает boolean, и было бы логично использовать это значение. А оно игнорируется.
Адаптер
- Опять же, зачем везде var? Можно мутировать menuItems и вызвать inconsistency. Можно мутировать itemLayoutId и изменить item view прямо во время работы адаптера. Неужели это должно быть разрешено?
- var itemLayoutId: Int = 0 — какой смысл в layout с нулевым ID?
open class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
var imageIcon: ImageView = itemView?.findViewById(R.id.image_icon) as ImageView
var textTitle: TextView = itemView?.findViewById(R.id.text_title) as TextView
}
Отличный пример использования nullability не по назначению. Можно передать null вместо view, тогда выражение itemView?.findViewById(R.id.image_icon) будет равно null, а его никак не скастить в ImageView.