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 тестване, feature flags). За статични зависимости Hilt напълно автоматизира създаването на обекти — разработчикът пише само интерфейса и анотациите.
Често задавани въпроси
Factory Method създава един тип обект чрез наследяване — подкласът презаписва фабричния метод. Abstract Factory създава фамилия от обекти чрез композиция — интерфейсът на фабриката декларира методи за няколко продукта. Factory Method е по-прост, Abstract Factory е по-гъвкав за платформозависими или тематични компоненти.
Factory е оправдана за динамичен избор на имплементация по време на изпълнение (A/B тестове, feature flags, различно API за различни тарифи). DI (Hilt, Dagger, Koin) е за предпочитане за статични зависимости — той автоматизира създаването и инжектирането. Factory и DI не се изключват взаимно: DI може да използва Factory вътре в модул.
Factory се тества чрез замяна на фабриката чрез протокол. В теста се създава TestFactory, която имплементира същия протокол и връща mock-обекти. За статични Factory методи тестването е по-трудно — изисква DI контейнер или swizzling. Препоръчва се винаги да се използва протокол за Factory, за да се запази тестваемостта.
ViewModelProvider.Factory — интерфейс от Jetpack, който позволява създаване на ViewModel с персонализирани параметри. Без фабрика ViewModel се създава чрез рефлексия и може да има само празен конструктор. Factory приема параметри (repository, application context) и ги предава на конструктора на ViewModel. Hilt генерира Factory автоматично за @HiltViewModel.
Factory реализира принципа Open-Closed: системата е отворена за разширение (нова имплементация се добавя във фабриката), но затворена за модификация (клиентският код не се променя). Добавянето на нов тип продукт изисква промяна само във фабриката, а не във всички клиенти. Това е ключовото предимство на Factory пред директното създаване на обекти.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също