03. Factory Method va Abstract Factory: Moslashuvchan UI va Gateway
🏛️ iOS Design Patterns — Mukammal Enterprise & Architecture Qo‘llanma
03. Creational: Factory Method va Abstract Factory
"Yangi mahsulot turi (masalan, yangi to'lov tizimi yoki yangi UI kartochkasi) qo'shilganda, agar siz mavjud 10 ta fayldagi
switch-casekodlarini ochib o'zgartirishga majbur bo'layotgan bo'lsangiz — siz Open/Closed tamoyilini buzdingiz. Factory aynan shu muammoni ildizi bilan yo'q qiladi."
1. Factory Method vs Abstract Factory: Asosiy Farq Nima?
Ko'p dasturchilar bu ikki patternni aralashtirib yuborishadi. Oddiy qoida:
- Factory Method: Faqat bitta mahsulotni yaratishga mas'ul (masalan:
createPaymentGateway() -> PaymentGateway). - Abstract Factory: Bir-biriga mantiqan bog'liq bo'lgan butun mahsulotlar oilasini yaratishga mas'ul (masalan:
createButton(),createAlert(),createTextField()).
graph TD
subgraph FM["1. Factory Method (1 ta mahsulot)"]
direction TB
FMethod["PaymentFactory.create(type)"] --> Gateway["Bitta Gateway qaytadi\n(Payme, Click yoki ApplePay)"]
end
subgraph AF["2. Abstract Factory (Mahsulotlar Oilasi)"]
direction TB
AFactory["UIThemeFactory (Interfeys)"]
AFactory --> DarkF["DarkThemeFactory"]
AFactory --> LightF["LightThemeFactory"]
DarkF --> DarkBtn["Dark Button"]
DarkF --> DarkAlert["Dark Alert"]
DarkF --> DarkField["Dark TextField"]
LightF --> LightBtn["Light Button"]
LightF --> LightAlert["Light Alert"]
LightF --> LightField["Light TextField"]
end
style FM fill:#131720,stroke:#7da2ce,stroke-width:1px
style AF fill:#131720,stroke:#bef264,stroke-width:2px
2. Factory Method: Real FinTech To'lov Tizimi Misoli
Tasavvur qiling, ilovangizda Payme, Click va Apple Pay orqali to'lov mavjud.
Nega oddiy switch-case xato?
// ❌ OCP ni buzuvchi yondashuv:
func pay(type: String, amount: Double) {
switch type {
case "payme": PaymeSDK.charge(...)
case "click": ClickSDK.charge(...)
// Yangi 'uzum' qo'shilsa, bu kodni ochib o'zgartirish shart!
}
}
To'g'ri Factory Method Yechimi:
// 1. Umumiy Mahsulot Protokoli
public protocol PaymentGateway: Sendable {
func processPayment(amount: Double) async throws -> String
}
// 2. Aniq Mahsulotlar (Concrete Products)
public final class PaymeGateway: PaymentGateway {
public func processPayment(amount: Double) async throws -> String {
return "Payme orqali \(amount) so'm to'landi. Tranzaksiya: #PAY_102"
}
}
public final class ClickGateway: PaymentGateway {
public func processPayment(amount: Double) async throws -> String {
return "Click orqali \(amount) so'm to'landi. Tranzaksiya: #CLK_904"
}
}
public final class ApplePayGateway: PaymentGateway {
public func processPayment(amount: Double) async throws -> String {
return "Apple Pay orqali \(amount) so'm to'landi. Tranzaksiya: #APL_551"
}
}
// 3. Factory Method
public enum PaymentMethodType {
case payme
case click
case applePay
}
public struct PaymentGatewayFactory {
public static func makeGateway(for type: PaymentMethodType) -> any PaymentGateway {
switch type {
case .payme:
return PaymeGateway()
case .click:
return ClickGateway()
case .applePay:
return ApplePayGateway()
}
}
}
Endi ViewModel faqat PaymentGateway protokoli bilan ishlaydi. U Payme yoki Click qanday ishlashini bilishga majbur emas!
3. Abstract Factory: Multi-Brand & Multi-Theme UI Dvigateli
Bir xil ilovani 2 xil brend (masalan, Oq brend va Qora VIP brend) yoki iOS va macOS uchun chiqarmoqchisiz:
classDiagram
class UIComponentFactory {
<<interface>>
+createButton() View
+createCard() View
+createBadge() View
}
class StandardThemeFactory {
+createButton() StandardButton
+createCard() StandardCard
+createBadge() StandardBadge
}
class VIPGoldThemeFactory {
+createButton() GoldButton
+createCard() GoldCard
+createBadge() GoldBadge
}
UIComponentFactory <|.. StandardThemeFactory
UIComponentFactory <|.. VIPGoldThemeFactory
Swift 6 Implementatsiyasi:
import SwiftUI
// 1. Mahsulotlar protokollari
public protocol ThemedButton: View {}
public protocol ThemedCard: View {}
// 2. Abstrakt Fabrika Protokoli (Butun oilani birlashtiradi)
public protocol AppThemeFactory {
associatedtype ButtonView: ThemedButton
associatedtype CardView: ThemedCard
func makeButton(title: String, action: @escaping () -> Void) -> ButtonView
func makeCard(title: String, subtitle: String) -> CardView
}
// 3. Aniq Fabrika #1: Standart Mavzu
public struct StandardThemeFactory: AppThemeFactory {
public func makeButton(title: String, action: @escaping () -> Void) -> some ThemedButton {
StandardButtonImpl(title: title, action: action)
}
public func makeCard(title: String, subtitle: String) -> some ThemedCard {
StandardCardImpl(title: title, subtitle: subtitle)
}
}
// 4. Aniq Fabrika #2: VIP Oltin Mavzu
public struct VIPGoldThemeFactory: AppThemeFactory {
public func makeButton(title: String, action: @escaping () -> Void) -> some ThemedButton {
GoldButtonImpl(title: title, action: action)
}
public func makeCard(title: String, subtitle: String) -> some ThemedCard {
GoldCardImpl(title: title, subtitle: subtitle)
}
}
// Komponentlarning aniq SwiftUI ko'rinishlari
private struct StandardButtonImpl: ThemedButton {
let title: String
let action: () -> Void
var body: some View {
Button(title, action: action)
.buttonStyle(.borderedProminent)
.tint(.blue)
}
}
private struct GoldButtonImpl: ThemedButton {
let title: String
let action: () -> Void
var body: some View {
Button(title, action: action)
.buttonStyle(.borderedProminent)
.tint(.yellow)
.foregroundColor(.black)
}
}
private struct StandardCardImpl: ThemedCard {
let title: String
let subtitle: String
var body: some View {
VStack { Text(title); Text(subtitle) }.padding().background(Color.gray.opacity(0.1))
}
}
private struct GoldCardImpl: ThemedCard {
let title: String
let subtitle: String
var body: some View {
VStack { Text(title); Text(subtitle) }.padding().background(Color.yellow.opacity(0.2))
}
}
4. Qachon Qaysi Biri Ishlatiladi?
| Mezon | Factory Method | Abstract Factory |
|---|---|---|
| Yaratiladigan Obyektlar Soni | 1 ta alohida obyekt | Bir-biriga bog'liq bir nechta obyektlar oilasi |
| Murakkablik Darajasi | Past va tushunarli | O'rtacha/Yuqori (ko'plab protokollar talab etiladi) |
| Qo'llash Joyi | Parserlar, To'lov tizimlari, Network Clientlar | Multi-Brand tizimlar, Dizayn Tizimlari, Platformlararo UI |
5. Interaktiv Savol-Javob (Self-Check Quiz)
<details> <summary><b>1-Savol: Nega Factory patterni Open/Closed (SOLID O) tamoyilini eng zo'r himoya qiluvchi pattern hisoblanadi?</b> (Yechimni ko'rish uchun bosing)</summary>
Tahlil va Yechim: Chunki ilovaning biznes logikasi (masalan, Savat yoki To'lov ViewModel'i) aniq sinflar (PaymeGateway, ClickGateway) ga emas, umumiy PaymentGateway protokoliga bog'langan bo'ladi. Yangi to'lov turi (masalan, UzumPay) qo'shilganda mavjud ViewModel'larning birorta satr kodiga tegilmaydi! Faqat yangi UzumPayGateway sinfi yoziladi va fabrikaga qo'shiladi. Kod o'zgarishlarga yopiq, kengayishga ochiq bo'ladi. </details>
<details> <summary><b>2-Savol: Swift'da Dependency Injection Container va Factory o'rtasida qanday farq bor?</b> (Yechimni ko'rish uchun bosing)</summary>
Tahlil va Yechim: Factory odatda berilgan parametrlar (type, config) asosida har safar yangi instancelar yaratib berishga xizmat qiladi. DI Container esa barcha ilova xizmatlarining (Singletons, Transient, Scoped xizmatlar) hayot siklini boshqaruvchi markazlashgan registrator hisoblanadi. Ko'p hollarda DI Container o'z ichida Factory patternidan foydalanadi. </details>
6. Amaliy Topshiriq (Senior Challenge)
Ilovangiz uchun DocumentExporterFactory yarating:
PDFExporter,CSVExportervaJSONExportersinflari bittaDocumentExportingprotokolini tasdiqlasin.makeExporter(for format: ExportFormat)orqali kerakli formatga o'tkazuvchi Factory Method yozing.- Foydalanuvchi ma'lumotlarini 3 xil formatda eksport qilishni simulyatsiya qilib ko'ring!