Factory — порождающий паттерн, делегирующий создание объектов фабричным методам. В мобильной разработке Factory Method и Abstract Factory используются для создания ViewModel, NetworkClient, Repository и других зависимостей. Factory изолирует логику инстанцирования, упрощая замену реализаций. Подробнее — в Refactoring Guru: Factory Method.
Главное
Factory — порождающий паттерн проектирования из каталога GoF. Основная идея: вынести логику создания объектов из клиентского кода в отдельный метод или класс. Клиент работает с интерфейсом или абстрактным классом, а конкретная реализация создаётся фабрикой. Это реализует принцип инверсии зависимостей (Dependency Inversion): клиент не зависит от конкретных классов, только от абстракций.
Две разновидности Factory: Factory Method и Abstract Factory. Factory Method — один метод в классе, который подклассы переопределяют для создания объектов. Abstract Factory — интерфейс с семейством фабричных методов для создания групп взаимосвязанных объектов. Оба варианта решают одну задачу: клиент не вызывает new MyClass() напрямую, а просит фабрику создать объект по его типу или параметрам.
Factory vs new() — прямое создание объектов жёстко связывает код с конкретной реализацией. Factory добавляет прослойку: изменение реализации требует правки только в фабрике, а не во всех клиентах. В мобильной разработке Factory активно используется для создания ViewModel (ViewModelProvider.Factory), сетевых клиентов (Retrofit.create()), адаптеров списков и фабрик сериализации. DI-контейнеры (Dagger, Koin) автоматически генерируют фабрики.
Factory Method — метод, объявленный в протоколе или абстрактном классе, который возвращает объект определённого типа. Подклассы реализуют метод, создавая конкретные экземпляры. В Swift это может быть static method в протоколе или метод в базовом классе. В Kotlin — companion object с фабричным методом или open fun в абстрактном классе. Паттерн широко применяется для создания парсеров, фабрик ошибок и строителей запросов.
protocol PaymentGateway {
func processPayment(amount: Decimal) async throws -> PaymentResult
}
final class StripeGateway: PaymentGateway { /* ... */ }
final class ApplePayGateway: PaymentGateway { /* ... */ }
enum PaymentType { case stripe, applePay }
final class PaymentFactory {
// Factory Method
static func create(type: PaymentType) -> PaymentGateway {
switch type {
case .stripe: return StripeGateway()
case .applePay: return ApplePayGateway()
}
}
}
// Использование
let gateway = PaymentFactory.create(type: .stripe)
Kotlin-версия Factory Method использует companion object или sealed class для ограничения типов. Sealed class гарантирует, что ветка when покрывает все возможные типы — компилятор проверяет полноту. Это типично для Android-проектов, где фабрика создаёт разные реализации Repository или DataSource в зависимости от build flavour или конфигурации.
sealed class PaymentType {
object Stripe : PaymentType()
object ApplePay : PaymentType()
}
interface PaymentGateway {
suspend fun processPayment(amount: BigDecimal): PaymentResult
}
class PaymentFactory {
companion object {
fun create(type: PaymentType): PaymentGateway = when (type) {
PaymentType.Stripe -> StripeGateway()
PaymentType.ApplePay -> ApplePayGateway()
}
}
}
Abstract Factory — паттерн для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов. Клиент работает с интерфейсом абстрактной фабрики, который определяет методы для создания каждого продукта семейства. Конкретная фабрика реализует интерфейс и создаёт объекты определённого варианта. Например, фабрика UI-компонентов для iOS создаёт UIButton, UILabel, UITableView, а для Android — Button, TextView, RecyclerView.
Abstract Factory vs Factory Method — Factory Method создаёт один тип объекта через наследование, Abstract Factory создаёт семейство объектов через композицию. Factory Method переопределяется в подклассах, Abstract Factory предоставляет несколько фабричных методов через протокол. Abstract Factory часто содержит несколько Factory Method. В мобильной разработке Abstract Factory используется для платформозависимых компонентов, тем оформления и фабрик баз данных.
| Характеристика | Factory Method | Abstract Factory |
|---|---|---|
| Количество продуктов | Один | Семейство (несколько) |
| Механизм | Наследование (override) | Композиция (protocol/interface) |
| Пример iOS | PaymentFactory.create() | UIComponentFactory для iOS/Android |
| Пример Android | ViewModelProvider.Factory | ThemeFactory: создание кнопок, текстов, карточек |
| Гибкость | Простая замена подкласса | Полная замена семейства |
Реальный кейс Abstract Factory в Android — реализация разных типов баз данных (SQLite vs Room) через единый интерфейс DatabaseFactory. Фабрика создаёт DAO-объекты, миграции и пулы соединений. В iOS — фабрика сервисов для разных сред (Development/Staging/Production). Abstract Factory редко используется напрямую — её функции берут на себя DI-контейнеры (Dagger Module, Swinject Assembly).
Swift Factory реализуется через протоколы и статические методы. Протокол Factory объявляет метод create(), возвращающий абстрактный тип. Конкретная фабрика реализует протокол и создаёт нужные объекты. Swift не требует отдельного класса-фабрики для простых случаев — достаточно статического метода в enum или struct. Для сложных сценариев используется Factory-протокол с внедрением через DI.
Factory в iOS SDK — множество системных фабрик: UIStoryboard.instantiateViewController(withIdentifier:), NSKeyedUnarchiver.unarchivedObject(ofClass:from:), JSONDecoder().decode(_:from:). Разработчики создают фабрики для ViewController (StoryboardFactory), для сервисов (ServiceFactory) и для моделей данных. Factory Method активно используется в архитектурах VIPER и Clean Swift для создания модулей экранов.
Factory + DI — современная альтернатива: DI-контейнер (Swinject, Factory) автоматически генерирует фабрики для зарегистрированных типов. Контейнер хранит рецепты создания объектов и разрешает зависимости. Factory-библиотека (github.com/hmlongco/Factory) использует @Injected(.service) для автоматического внедрения. DI-фабрики тестируются заменой целого модуля одной строкой: container.register { MockService() }.
Android Factory — классический пример: ViewModelProvider.Factory для создания ViewModel с параметрами. Google рекомендует использовать Hilt для автоматической генерации фабрик ViewModel — аннотация @HiltViewModel создаёт Factory автоматически. Для простых объектов используется companion object с методом create() или invoke(). В Kotlin оператор invoke позволяет вызывать фабрику как функцию: Factory(param).
Factory в Jetpack Compose — фабрики используются для создания состояний и эффектов. remember { Factory.create() } создаёт объект при первом рендеринге и сохраняет его на время жизни composable. ViewModel в Compose создаётся через viewModel() — это фабрика, управляемая Hilt. В Compose фабрики реже встречаются явно, так как DI и Compose StateManager берут на себя создание объектов.
Factory vs Hilt — Dagger/Hilt автоматически генерирует фабрики на этапе компиляции. @Module + @Provides заменяет Factory Method, @Binds заменяет Abstract Factory. Ручные фабрики остаются актуальными для динамического выбора реализации в рантайме (A/B тестирование, фича-флаги). Для статических зависимостей Hilt полностью автоматизирует создание объектов — разработчик пишет только интерфейс и аннотации.
Часто задаваемые вопросы
Factory Method создаёт один тип объекта через наследование — подкласс переопределяет фабричный метод. Abstract Factory создаёт семейство объектов через композицию — интерфейс фабрики объявляет методы для нескольких продуктов. Factory Method проще, Abstract Factory гибче для платформозависимых или тематических компонентов.
Factory оправдана для динамического выбора реализации в рантайме (A/B тесты, фича-флаги, разный API для разных тарифов). DI (Hilt, Dagger, Koin) предпочтительнее для статических зависимостей — он автоматизирует создание и внедрение. Factory и DI не исключают друг друга: DI может использовать Factory внутри модуля.
Factory тестируется подменой фабрики через протокол. В тесте создаётся TestFactory, реализующая тот же протокол и возвращающая mock-объекты. Для статических Factory-методов тестирование сложнее — потребуется DI-контейнер или swizzling. Рекомендуется всегда использовать протокол для Factory, чтобы сохранить тестируемость.
ViewModelProvider.Factory — интерфейс из Jetpack, позволяющий создавать ViewModel с кастомными параметрами. Без фабрики ViewModel создаётся через рефлексию и может иметь только пустой конструктор. Factory принимает параметры (репозиторий, application context) и передаёт их в конструктор ViewModel. Hilt генерирует Factory автоматически для @HiltViewModel.
Factory реализует Open-Closed Principle: система открыта для расширения (новая реализация добавляется в фабрику), но закрыта для модификации (клиентский код не меняется). Добавление нового типа продукта требует правки только в фабрике, а не во всех клиентах. Это ключевое преимущество Factory перед прямым созданием объектов.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также