1. Порождающие паттерны: Singleton, Builder и Factory Method в Android SDK
Порождающие паттерны: Singleton, Builder и Factory Method в Android SDK
Добро пожаловать на курс «Паттерны проектирования в Android-разработке». Это первая статья нашего цикла, и мы начнем с фундамента — порождающих паттернов (Creational Patterns).
В программировании, как и в архитектуре зданий, существуют типовые решения для часто встречающихся проблем. Эти решения называют паттернами проектирования. Они не являются готовым кодом, который можно просто скопировать (хотя иногда это так выглядит), а скорее представляют собой описание взаимодействия классов и объектов.
Сегодня мы разберем три самых популярных порождающих паттерна, которые вы неизбежно встретите в Android SDK и будете использовать в своих приложениях: Singleton (Одиночка), Builder (Строитель) и Factory Method (Фабричный метод).
Зачем нужны порождающие паттерны?
Порождающие паттерны абстрагируют процесс инстанцирования (создания) объектов. Они помогают сделать систему независимой от того, как именно создаются, компонуются и представляются её объекты.
Простыми словами: вместо того чтобы просто писать new ClassName(), мы используем хитрые механизмы, которые дают нам гибкость, контроль и чистоту кода.
---
1. Singleton (Одиночка)
Суть паттерна
Singleton — это паттерн, который гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Представьте, что в вашем офисе есть один главный принтер. Неважно, кто отправляет документ на печать — бухгалтер с третьего этажа или менеджер с первого — все запросы идут к одному и тому же физическому устройству. Если бы каждый создавал свой «виртуальный принтер», возник хаос. В программировании Singleton часто используется для объектов, которые управляют общими ресурсами: базой данных, сетевым клиентом или настройками приложения.
!Диаграмма, показывающая, как множество клиентов обращаются к единственному экземпляру Singleton.
Реализация в Kotlin
В Java реализация Singleton требовала написания приватного конструктора и статического метода getInstance(), часто с добавлением синхронизации для потокобезопасности (Double Check Locking). В Kotlin этот паттерн встроен в сам язык с помощью ключевого слова object.
Singleton в Android SDK
Android SDK активно использует концепцию Singleton, хотя часто скрывает её за вызовами методов. Классический пример — системные сервисы.
Когда вы вызываете context.getSystemService(Context.INPUT_METHOD_SERVICE), вы не создаете новый менеджер ввода каждый раз. Система возвращает вам ссылку на уже существующий сервис, который управляет клавиатурой во всей системе.
Другой пример — класс Application. Хотя технически это не чистый Singleton (система создает его за вас), в рамках процесса вашего приложения он существует в единственном экземпляре и часто используется для хранения глобального состояния.
Когда использовать, а когда нет
Плюсы: * Гарантия единственного экземпляра. * Глобальный доступ (удобно, но опасно). * Ленивая инициализация (объект создается только при первом обращении).
Минусы:
* Нарушение принципа единственной ответственности (SRP): класс управляет и своей логикой, и своим созданием.
* Проблемы с тестированием: глобальное состояние очень трудно подменять (mock) в Unit-тестах.
* Скрытые зависимости: если ваш класс внутри себя вызывает NetworkManager.makeRequest, это не видно в его конструкторе.
> Используйте Singleton осторожно. В современной Android-разработке часто предпочитают использовать Dependency Injection (например, Hilt или Koin), где объект помечается как @Singleton, но передается через конструктор.
---
2. Builder (Строитель)
Суть паттерна
Builder — это паттерн, который позволяет создавать сложные объекты пошагово. Он отделяет конструирование сложного объекта от его представления.
Представьте, что вы заказываете пиццу. Вы не просто говорите «дай мне пиццу». Вы говорите: «Тесто тонкое, соус томатный, добавь пепперони, убери лук, добавь сыр». Вы «строите» свой заказ шаг за шагом. Если бы для каждой комбинации ингредиентов существовал отдельный класс (например, PizzaThinDoughTomatoSaucePepperoniNoOnion), у нас были бы тысячи классов.
В коде Builder спасает нас от так называемого «телескопического конструктора», когда у класса 10 параметров, и половина из них — null.
!Визуализация пошагового процесса сборки сложного объекта.
Builder в Android SDK
Самый известный пример в Android — создание диалоговых окон AlertDialog и уведомлений Notification.
Взгляните на этот код:
Здесь AlertDialog.Builder — это вложенный класс, который накапливает настройки. Метод create() (или build()) собирает все параметры и выдает готовый объект AlertDialog.
Еще один пример — Retrofit. Для создания экземпляра мы используем билдер:
Реализация своего Builder в Kotlin
В Kotlin потребность в классическом паттерне Builder снижается благодаря именованным аргументам и значениям по умолчанию.
Вместо громоздкого Билдера:
В Kotlin мы пишем:
Однако, если инициализация объекта требует сложной логики (валидация комбинации полей, последовательные вычисления), паттерн Builder всё еще актуален даже в Kotlin.
---
3. Factory Method (Фабричный метод)
Суть паттерна
Factory Method — это паттерн, который определяет интерфейс для создания объекта, но позволяет подклассам решать, какой класс инстанцировать. Фабричный метод позволяет классу делегировать создание объектов своим подклассам.
Аналогия из жизни: логистическая компания. У неё есть метод «Доставить груз». Если это автоперевозки, создается объект «Грузовик». Если морские перевозки — создается объект «Корабль». Клиентский код (менеджер) просто говорит «Доставить», не вдаваясь в подробности, как именно будет создан транспорт.
Factory Method в Android SDK
Отличный пример — ViewModelProvider.Factory.
В Android ViewModel не может быть создана просто через конструктор, если у неё есть параметры, потому что её жизненным циклом управляет система. Нам нужно подсказать системе, как создавать нашу ViewModel.
Здесь метод create — это и есть тот самый фабричный метод. Фреймворк Android вызовет его, когда ему потребуется экземпляр MyViewModel, и фабрика вернет готовый объект с внедренным репозиторием.
Еще один пример, с которым вы сталкиваетесь постоянно — LayoutInflater.
Метод inflate работает как фабрика: он читает XML-файл и на его основе создает иерархию объектов View (TextView, Button, LinearLayout и т.д.). Вы не пишете new TextView(...) вручную для каждого элемента, это делает фабрика.
Статический фабричный метод
Частный случай, популярный в Java и Android — статические методы создания. Например, в Fragment:
Метод newInstance скрывает сложность настройки фрагмента (создание Bundle, установка аргументов) и возвращает готовый объект. Это упрощает использование класса для внешнего кода.
---
Итоги
Мы рассмотрели три ключевых порождающих паттерна:
Понимание этих паттернов поможет вам не только писать более чистый код, но и лучше понимать, как работает сам Android SDK под капотом. В следующей статье мы перейдем к структурным паттернам и узнаем, как эффективно компоновать объекты и классы.