Factory — породжувальний патерн, що делегує створення об'єктів фабричним методам. У мобільній розробці Factory Method та Abstract Factory використовуються для створення ViewModel, NetworkClient, Repository та інших залежностей. Factory ізолює логіку інстанціювання, спрощуючи заміну реалізацій. Детальніше — на Refactoring Guru: Factory Method.
Головне
Factory — породжувальний патерн проєктування з каталогу GoF. Основна ідея: винести логіку створення об'єктів з клієнтського коду в окремий метод або клас. Клієнт працює з інтерфейсом або абстрактним класом, а конкретна реалізація створюється фабрикою. Це реалізує принцип інверсії залежностей: клієнт не залежить від конкретних класів, лише від абстракцій.
Дві різновидності 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також