05. Adapter: Eski Callback SDK ni Zamonaviy Swift 6 ga Moslash
🏛️ iOS Design Patterns — Mukammal Enterprise & Architecture Qo‘llanma
05. Structural: Adapter Pattern — Eski va Yangi Dunyo Ko'prigi
"Siz yangi uyingizga eng zamonaviy yevro-vilka sotib oldingiz, ammo devordagi rozetka eski sovet standartida. Rozetkani buzib devorni sindirasizmi yoki 1 dollarlik o'tish moslamasi (adapter) qo'yasizmi? Adapter patterni dasturiy ta'minotning aynan o'sha o'tish moslamasidir."
1. Adapter Pattern Nima va U Qaysi Muammoni Hal Qiladi?
Adapter (Wrapper) — bu ikki xil mos kelmaydigan interfeysga ega bo'lgan sinflarni bir-biri bilan hamkorlikda ishlashiga imkon beruvchi tuzilmaviy pattern.
flowchart LR
Client["Bizning Swift 6 Ilovamiz\n(Kutadi: async/await Protocol)"] --> Adapter["LocationServiceAdapter\n(Moslashtiruvchi Ko'prik)"]
Adapter --> LegacySDK["Eski 3rd Party SDK\n(Obj-C / Callback Closures / Delegates)"]
style Client fill:#131720,stroke:#bef264,stroke-width:2px
style Adapter fill:#181d26,stroke:#7da2ce,stroke-width:2px
style LegacySDK fill:#251014,stroke:#f87171,stroke-width:1px
Haqiqiy iOS Loyihalardagi Muammo:
- Kompaniyangiz eski Objective-C da yozilgan yoki begona kompaniyaning xunuk SDK'sini (masalan, eski Xaritalar yoki To'lov SDK'si) ishlatishga majbur.
- Bu SDK eski completion-handler callbacklar yoki murakkab xunuk metodlar bilan ishlaydi.
- Agar siz butun ViewModel va Use Case laringiz ichiga o'sha xunuk SDK sinflarini to'g'ridan-to'g'ri chaqirib yozsangiz, ertaga o'sha SDK'ni boshqasiga (masalan, Google Maps'dan Apple MapKit'ga) almashtirishga to'g'ri kelsa — butun loyihaning 50 ta faylini qayta yozishingizga to'g'ri keladi!
2. Class Adapter vs Object Adapter: Nega Swift'da Composition G'alaba Qozonadi?
Nazariyada ikkita turli Adapter mavjud:
- Class Adapter: Vorislik (Inheritance) orqali eski sinfdan meros oladi va yangi protokolni tasdiqlaydi. Swift'da ko'p karra vorislik (Multiple Inheritance) taqiqlangani sababli bu usul deyarli ishlatilmaydi.
- Object Adapter: Kompozitsiya (Composition) orqali eski SDK'ni o'zining ichida xususiy (private) obyekt sifatida saqlaydi va unga so'rovlarni uzatadi. Bu eng xavfsiz va moslashuvchan yo'ldir.
3. Real-World Swift 6 Kodi: Callback SDK ni async/await ga Moslash
Keling, eski 3rd party GPS SDK'sini zamonaviy Swift 6 talablariga moslashtiramiz.
1. Eski Tashqi SDK (Biz uning kodini o'zgartira olmaymiz):
// Begona kompaniya kutubxonasi (Legacy SDK)
public final class LegacyTrackerSDK {
public func fetchCoordinates(completion: @escaping (Double, Double, Error?) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
// Sun'iy koordinata qaytarish
completion(41.311081, 69.240562, nil)
}
}
}
2. Bizning Loyihamiz Qabul Qiladigan Zamonaviy Kontrakt:
public struct UserLocation: Sendable {
public let latitude: Double
public let longitude: Double
}
public protocol LocationService: Sendable {
func getCurrentLocation() async throws -> UserLocation
}
3. Object Adapter:
public enum LocationError: Error {
case locationUnavailable
}
public final class LegacyLocationAdapter: LocationService {
private let legacySDK: LegacyTrackerSDK
public init(legacySDK: LegacyTrackerSDK = LegacyTrackerSDK()) {
self.legacySDK = legacySDK
}
public func getCurrentLocation() async throws -> UserLocation {
// Swift Concurrency ning CheckedContinuation imkoniyati
// eski callback'ni zamonaviy async/await ga o'girishda eng yaxshi adapterdir!
return try await withCheckedThrowingContinuation { continuation in
legacySDK.fetchCoordinates { lat, lng, error in
if let error = error {
continuation.resume(throwing: error)
} else {
let location = UserLocation(latitude: lat, longitude: lng)
continuation.resume(returning: location)
}
}
}
}
}
4. ViewModel'da Ishlatilishi:
@MainActor
public final class MapViewModel {
private let locationService: any LocationService
public init(locationService: any LocationService) {
self.locationService = locationService
}
public func updatePosition() async {
do {
let loc = try await locationService.getCurrentLocation()
print("Foydalanuvchi manzili: \(loc.latitude), \(loc.longitude)")
} catch {
print("Xatolik: \(error)")
}
}
}
4. Katta Yutuq: SDK ni 1 Soniyada Almashtirish
Tasavvur qiling, 6 oydan keyin kompaniya rahbariyati: "LegacyTrackerSDK juda qimmat ekan, keling Apple'ning CoreLocation tizimiga o'tamiz" dedi.
Siz ViewModel yoki ekranlarga birorta ham o'zgartirish kiritmaysiz! Siz shunchaki yangi CoreLocationAdapter yozasiz va Dependency Injection orqali uzatasiz:
public final class AppleCoreLocationAdapter: LocationService {
public func getCurrentLocation() async throws -> UserLocation {
// CoreLocation async API
return UserLocation(latitude: 41.31, longitude: 69.24)
}
}
Bu toza arxitekturaning va Adapter patternining chinakam qudratidir!
5. Interaktiv Savol-Javob (Self-Check Quiz)
<details> <summary><b>1-Savol: Swift'da 'withCheckedContinuation' va 'withCheckedThrowingContinuation' funksiyalari qanday qilib til darajasidagi Adapter hisoblanadi?</b> (Yechimni ko'rish uchun bosing)</summary>
Tahlil va Yechim: Ushbu funksiyalar eski oqim (Completion-handler / Delegate) interfeysini qabul qilib, uni Swift Concurrency (async/await) ga moslashtirib beruvchi standart Apple adapteri vazifasini bajaradi. Ular eski asinxron kodni to'xtatib turadi (await) va natija kelganda davom ettiradi (resume). </details>
<details> <summary><b>2-Savol: Adapter va Facade patternlarining asosiy farqi nimada?</b> (Yechimni ko'rish uchun bosing)</summary>
Tahlil va Yechim:
- Adapter mavjud interfeysni boshqa bir aniq kutilayotgan interfeysga moslashtirish (Convert/Translate qilish) uchun ishlatiladi.
- Facade esa interfeysni moslashtirmaydi, balki ko'plab murakkab tizimlarning ustiga yangidan bitta sodda boshqaruv oynasi qurib beradi (Simplification).
</details>
6. Amaliy Topshiriq (Senior Challenge)
Ilovangizda eski NotificationCenter orqali xabar uzatuvchi tizim mavjud:
- Ushbu eski xabarlashuvni
AsyncStream<String>orqali zamonaviy Swift 6 oqimiga aylantirib beruvchiNotificationCenterAdaptersinfini yarating!