Factory — wzorzec kreacyjny, który deleguje tworzenie obiektów do metod fabrycznych. W programowaniu mobilnym Factory Method i Abstract Factory są używane do tworzenia ViewModel, NetworkClient, Repository i innych zależności. Factory izoluje logikę tworzenia instancji, ułatwiając wymianę implementacji. Więcej — w Refactoring Guru: Factory Method.
Najważniejsze
Factory — kreacyjny wzorzec projektowy z katalogu GoF. Główna idea: przenieść logikę tworzenia obiektów z kodu klienckiego do osobnej metody lub klasy. Klient pracuje z interfejsem lub klasą abstrakcyjną, a konkretna implementacja jest tworzona przez fabrykę. Realizuje to zasadę odwrócenia zależności (Dependency Inversion): klient nie zależy od konkretnych klas, tylko od abstrakcji.
Dwie odmiany Factory: Factory Method i Abstract Factory. Factory Method — jedna metoda w klasie, którą podklasy nadpisują w celu tworzenia obiektów. Abstract Factory — interfejs z rodziną metod fabrycznych do tworzenia grup powiązanych obiektów. Oba warianty rozwiązują to samo zadanie: klient nie wywołuje new MyClass() bezpośrednio, tylko prosi fabrykę o utworzenie obiektu według jego typu lub parametrów.
Factory vs new() — bezpośrednie tworzenie obiektów sztywno wiąże kod z konkretną implementacją. Factory dodaje warstwę pośrednią: zmiana implementacji wymaga modyfikacji tylko w fabryce, a nie we wszystkich klientach. W programowaniu mobilnym Factory jest aktywnie używana do tworzenia ViewModel (ViewModelProvider.Factory), klientów sieciowych (Retrofit.create()), adapterów list i fabryk serializacji. Kontenery DI (Dagger, Koin) automatycznie generują fabryki.
Factory Method — metoda zadeklarowana w protokole lub klasie abstrakcyjnej, która zwraca obiekt określonego typu. Podklasy implementują tę metodę, tworząc konkretne instancje. W Swift może to być static method w protokole lub metoda w klasie bazowej. W Kotlin — companion object z metodą fabryczną lub open fun w klasie abstrakcyjnej. Wzorzec jest szeroko stosowany do tworzenia parserów, fabryk błędów i builderów zapytań.
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()
}
}
}
// Użycie
let gateway = PaymentFactory.create(type: .stripe)
Wersja Kotlin Factory Method używa companion object lub sealed class do ograniczenia typów. Sealed class gwarantuje, że gałąź when pokrywa wszystkie możliwe typy — kompilator sprawdza kompletność. Jest to typowe dla projektów Android, gdzie fabryka tworzy różne implementacje Repository lub DataSource w zależności od build flavour lub konfiguracji.
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 — wzorzec do tworzenia rodzin powiązanych lub współzależnych obiektów bez określania ich konkretnych klas. Klient pracuje z interfejsem abstrakcyjnej fabryki, który definiuje metody tworzenia każdego produktu rodziny. Konkretna fabryka implementuje interfejs i tworzy obiekty określonego wariantu. Na przykład fabryka komponentów UI dla iOS tworzy UIButton, UILabel, UITableView, a dla Android — Button, TextView, RecyclerView.
Abstract Factory vs Factory Method — Factory Method tworzy jeden typ obiektu przez dziedziczenie, Abstract Factory tworzy rodzinę obiektów przez kompozycję. Factory Method jest nadpisywany w podklasach, Abstract Factory udostępnia kilka metod fabrycznych przez protokół. Abstract Factory często zawiera kilka Factory Method. W programowaniu mobilnym Abstract Factory jest używana do komponentów zależnych od platformy, motywów i fabryk baz danych.
| Cecha | Factory Method | Abstract Factory |
|---|---|---|
| Liczba produktów | Jeden | Rodzina (wiele) |
| Mechanizm | Dziedziczenie (override) | Kompozycja (protocol/interface) |
| Przykład iOS | PaymentFactory.create() | UIComponentFactory dla iOS/Android |
| Przykład Android | ViewModelProvider.Factory | ThemeFactory: tworzenie przycisków, tekstów, kart |
| Elastyczność | Prosta wymiana podklasy | Pełna wymiana rodziny |
Rzeczywisty przypadek Abstract Factory w Android — implementacja różnych typów baz danych (SQLite vs Room) przez jednolity interfejs DatabaseFactory. Fabryka tworzy obiekty DAO, migracje i pule połączeń. W iOS — fabryka usług dla różnych środowisk (Development/Staging/Production). Abstract Factory jest rzadko używana bezpośrednio — jej funkcje przejmują kontenery DI (Dagger Module, Swinject Assembly).
Swift Factory jest implementowana przez protokoły i metody statyczne. Protokół Factory deklaruje metodę create() zwracającą typ abstrakcyjny. Konkretna fabryka implementuje protokół i tworzy potrzebne obiekty. Swift nie wymaga osobnej klasy-fabryki dla prostych przypadków — wystarczy metoda statyczna w enum lub struct. Do złożonych scenariuszy używany jest protokół Factory z wstrzykiwaniem przez DI.
Factory w iOS SDK — wiele systemowych fabryk: UIStoryboard.instantiateViewController(withIdentifier:), NSKeyedUnarchiver.unarchivedObject(ofClass:from:), JSONDecoder().decode(_:from:). Deweloperzy tworzą fabryki dla ViewController (StoryboardFactory), dla usług (ServiceFactory) i dla modeli danych. Factory Method jest aktywnie używany w architekturach VIPER i Clean Swift do tworzenia modułów ekranów.
Factory + DI — nowoczesna alternatywa: kontener DI (Swinject, Factory) automatycznie generuje fabryki dla zarejestrowanych typów. Kontener przechowuje receptury tworzenia obiektów i rozwiązuje zależności. Biblioteka Factory (github.com/hmlongco/Factory) używa @Injected(.service) do automatycznego wstrzykiwania. Fabryki DI są testowane przez zastąpienie całego modułu jednym wierszem: container.register { MockService() }.
Android Factory — klasyczny przykład: ViewModelProvider.Factory do tworzenia ViewModel z parametrami. Google zaleca używanie Hilt do automatycznego generowania fabryk ViewModel — adnotacja @HiltViewModel tworzy Factory automatycznie. Dla prostych obiektów używany jest companion object z metodą create() lub invoke(). W Kotlin operator invoke pozwala wywoływać fabrykę jak funkcję: Factory(param).
Factory w Jetpack Compose — fabryki są używane do tworzenia stanów i efektów. remember { Factory.create() } tworzy obiekt przy pierwszym renderowaniu i zachowuje go na czas życia composable. ViewModel w Compose jest tworzony przez viewModel() — to fabryka zarządzana przez Hilt. W Compose fabryki rzadziej występują jawnie, ponieważ DI i Compose StateManager przejmują tworzenie obiektów.
Factory vs Hilt — Dagger/Hilt automatycznie generuje fabryki na etapie kompilacji. @Module + @Provides zastępuje Factory Method, @Binds zastępuje Abstract Factory. Ręczne fabryki pozostają istotne przy dynamicznym wyborze implementacji w czasie wykonania (testy A/B, flagi funkcji). Dla statycznych zależności Hilt w pełni automatyzuje tworzenie obiektów — deweloper pisze tylko interfejs i adnotacje.
Często zadawane pytania
Factory Method tworzy jeden typ obiektu przez dziedziczenie — podklasa nadpisuje metodę fabryczną. Abstract Factory tworzy rodzinę obiektów przez kompozycję — interfejs fabryki deklaruje metody dla kilku produktów. Factory Method jest prostszy, Abstract Factory jest bardziej elastyczny dla komponentów zależnych od platformy lub tematycznych.
Factory jest uzasadniona przy dynamicznym wyborze implementacji w czasie wykonania (testy A/B, flagi funkcji, różne API dla różnych taryf). DI (Hilt, Dagger, Koin) jest preferowane dla statycznych zależności — automatyzuje tworzenie i wstrzykiwanie. Factory i DI nie wykluczają się wzajemnie: DI może używać Factory wewnątrz modułu.
Factory jest testowana przez podmianę fabryki przez protokół. W teście tworzona jest TestFactory implementująca ten sam protokół i zwracająca obiekty mock. Dla statycznych metod Factory testowanie jest trudniejsze — wymaga kontenera DI lub swizzlingu. Zaleca się zawsze używać protokołu dla Factory, aby zachować testowalność.
ViewModelProvider.Factory — interfejs z Jetpack, umożliwiający tworzenie ViewModel z niestandardowymi parametrami. Bez fabryki ViewModel jest tworzony przez refleksję i może mieć tylko pusty konstruktor. Factory przyjmuje parametry (repozytorium, application context) i przekazuje je do konstruktora ViewModel. Hilt generuje Factory automatycznie dla @HiltViewModel.
Factory realizuje zasadę Open-Closed: system jest otwarty na rozszerzenia (nowa implementacja jest dodawana w fabryce), ale zamknięty na modyfikacje (kod kliencki się nie zmienia). Dodanie nowego typu produktu wymaga modyfikacji tylko w fabryce, a nie we wszystkich klientach. To kluczowa zaleta Factory przed bezpośrednim tworzeniem obiektów.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również