Разработка
Паттерн делегирования для написания многократно используемых компонентов Compose
В этой статье я расскажу о решении, позволяющем писать составные функции, которые в большей степени пригодны для повторного использования.
Одной из задач разработки программного обеспечения является создание многократно используемых компонентов, которые могут быть легко интегрированы в более крупную систему. Компонент — это часть кода, которая выполняет определенную функцию и может использоваться другими частями системы. Например, компонентом может быть кнопка, текст, чекбокс или изображение. Система может состоять из множества компонентов, которые взаимодействуют друг с другом, обеспечивая требуемую функциональность.
Однако добавление нового компонента в существующую систему не всегда просто. Это может потребовать изменения кода системы или других компонентов для размещения нового компонента.
Поэтому предполагается реализовать компоненты таким образом, чтобы они требовали минимальных изменений в будущем, когда мы захотим использовать их повторно.
В этой статье я расскажу о решении, позволяющем писать составные функции, которые в большей степени пригодны для повторного использования.
Проектирование
Атомарное проектирование (Atomic design) — ценная техника для создания многократно используемых составных компонентов.
Атомарный дизайн — это методология создания и поддержки согласованных, многократно используемых и масштабируемых компонентов пользовательского интерфейса. В ее основе лежит идея разбиения элементов пользовательского интерфейса на пять уровней абстракции: атомы, молекулы, организмы, шаблоны и страницы.
Чтобы использовать весь потенциал этих элементов, необходимо придерживаться правильного подхода к их реализации.
Ошибка
Ниже я покажу вам распространенную ошибку, с которой могут столкнуться разработчики при использовании Jetpack Compose.
🔴 Это неправильный способ создания пользовательского текстового компонента в Compose, поскольку он не имеет всех атрибутов текста, таких как цвет, модификатор, fontFamily и т.д.
// This is a wrong implementation for Compose components
fun HeaderText(
text: String,
) {
Text(
text = text,
style = MaterialTheme.typography.headlineLarge,
maxLines = 1,
)
}
// This is an usage
fun Usage() {
HeaderText(
text = "Products",
)
}
Основная проблема заключается в том, что если нам нужно изменить цвет HeaderText()
, то мы должны изменить его атрибуты.
xxxxxxxxxx
fun HeaderText(
text: String,
color: Color,
) {
Text(
text = text,
style = MaterialTheme.typography.headlineLarge,
color = color,
maxLines = 1,
)
}
Здесь можно увидеть изменения компонентов.
Решение
Используя паттерн делегирования, мы можем уменьшить количество изменений, которые необходимо внести в Compose компонент.
Делегирование — это просто передача обязанностей кому-то/чему-то другому. Делегирование может быть альтернативой наследованию.
Это означает использование свойств компонента в другом компоненте и передачу ему функциональности.
Преимущества:
- Минимальные изменения для добавления свойства в Compose компонент
- Разделение Compose компонентов и повышение возможности повторного использования
- Отсутствует необходимость написания менее используемых компонентов
Используя делегирование, мы можем унаследовать все поведение HeaderText()
от Text()
. Для этого мы передаем все параметры Text()
в HeaderText()
, присваивая им значения по умолчанию.
Кроме того, мы можем не передавать некоторые параметры Text()
, такие как textAlign
, softWrap
, style
, и определять их в HeaderText()
в зависимости от наших потребностей.
Мы завершили реализацию компонента HeaderText()
, использующего правило Делегирования.
xxxxxxxxxx
fun HeaderText(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
) {
Text(
text = text,
modifier = modifier,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = TextAlign.Center,
lineHeight = lineHeight,
overflow = overflow,
softWrap = false,
maxLines = maxLines,
onTextLayout = onTextLayout,
style = MaterialTheme.typography.headlineLarge,
)
}
Не забудьте добавить @NonRestartableComposable
к функции HeaderText()
.
Это предотвращает пропуск или перезапуск функции средой выполнения Compose. Это означает, что функция всегда будет выполняться при рекомпозиции ее родителя, и на нее не будут влиять изменения ее параметров или состояния.
Счетчик рекомпозиций для @NonRestartableComposable
:
HeaderText() с @NonRestartableComposable
HeaderText() без @NonRestartableComposable
Вернемся к первому примеру и разберем его более подробно.
Без делегирования 😥:
С делегированием:
Используя этот шаблон проектирования, разработчики могут создать набор для пользовательского интерфейса, содержащий множество составных компонентов, требующих минимальных изменений.
Заключение
В этой статье я рассказал, как использовать паттерн делегирования и паттерн атомарного проектирования для создания многократно используемых составных компонентов в Jetpack Compose. Применяя эти техники, мы можем избежать модификации кода компонентов или системы при добавлении нового свойства в компонент. Кроме того, мы можем разделить компоненты и способствовать их повторному использованию. Таким образом, мы можем повысить качество и удобство сопровождения разрабатываемого кода. Надеюсь, что эта статья была для вас полезной и вы узнали что-то новое.
Спасибо за прочтение.
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.14
-
Видео и подкасты для разработчиков4 недели назад
Исследуем мир фото и видео редакторов
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2025.13
-
Разработка2 недели назад
Конец продуктовой разработки в том виде, в котором мы ее знаем