Repository Pattern — biznes mantiq va ma'lumot manbalari o'rtasida abstraksiya qatlamini qo'shadigan naqsh. To'g'ridan-to'g'ri API, ma'lumotlar bazasi yoki kesh chaqiruvlari o'rniga Repository ma'lumotlarni olish va saqlash uchun yagona interfeysni taqdim etadi. Bu testlash va manbalar o'rtasida almashishni soddalashtiradi. Batafsil Android Data Layer hujjatlarida.
Asosiy
Repository Pattern — biznes mantiqni ma'lumot manbalariga to'g'ridan-to'g'ri kirishdan ajratib turadigan tuzilmaviy naqsh. Activity, UIViewController yoki ViewModel to'g'ridan-to'g'ri Retrofit, URLSession, Room yoki CoreData'ni chaqirish o'rniga Repository'ga murojaat qiladi. Repository ma'lumotlarni qayerdan olishni hal qiladi: tarmoqdan, ma'lumotlar bazasidan yoki keshdan va natijani yagona formatda qaytaradi. Bu yagona javobgarlik prinsipining amalga oshirilishi — UI ma'lumotlar qanday va qayerdan olinganligini bilmaydi.
Repository komponentlari interfeys (protocol), amalga oshirish va bir yoki bir nechta DataSource'ni o'z ichiga oladi. DataSource — bitta manba bilan ishlaydigan sinf: RemoteDataSource HTTP-klient orqali API'ni chaqiradi, LocalDataSource ma'lumotlar bazasiga o'qiydi va yozadi. Repository DataSource'larni konstruktor orqali qabul qiladi (Dependency Injection) va qaysi manbaga murojaat qilishni tanlaydi. Masalan, foydalanuvchilar ro'yxati so'rovida Repository avval keshni, keyin ma'lumotlar bazasini, so'ngra tarmoqni tekshiradi.
Afzalliklari Repository Pattern: ma'lumot manbalaridagi o'zgarishlar (API o'zgarishi, MB migratsiyasi) UI qatlamiga ta'sir qilmaydi; Repository yoki DataSource'ni almashtirish orqali unit testlash; UI uchun shaffof keshlash; ekran mantiqini o'zgartirmasdan online va offline rejimlari o'rtasida almashish. Android jamoasi Repository'ni Clean Architecture'da majburiy qatlam sifatida tavsiya qiladi.
iOS amalga oshirishi Repository Swift protokollariga asoslanadi. Repository protokoli ma'lumotlarni olish va saqlash uchun metodlarni e'lon qiladi. Haqiqiy amalga oshirish initsializator orqali kiritiladi — bu testlarda va SwiftUI preview'da amalga oshirishni almashtirishga imkon beradi. DataSource'lar ham protokollar bilan e'lon qilinadi: Protocol RemoteDataSource, Protocol LocalDataSource. ViewModel yoki Interactor aniq amalga oshirishni bilmaydi — faqat Repository protokolini biladi.
protocol UserRepository {
func getUsers() async throws -> [User]
}
protocol UserRemoteDataSource {
func fetchUsers() async throws -> [User]
}
protocol UserLocalDataSource {
func getCachedUsers() throws -> [User]
func saveUsers(_: [User]) throws
}
final class UserRepositoryImpl: UserRepository {
private let remote: UserRemoteDataSource
private let local: UserLocalDataSource
init(remote: UserRemoteDataSource, local: UserLocalDataSource) {
self.remote = remote
self.local = local
}
func getUsers() async throws -> [User] {
if let cached = try? local.getCachedUsers() {
return cached
}
let users = try await remote.fetchUsers()
try local.saveUsers(users)
return users
}
}
Dependency Injection iOS'da Repository uchun odatda fabrika yoki DI konteyneri (Swinject, Factory) orqali sozlanadi. Testlarda UserRepository protokoli oldindan belgilangan ma'lumotlarni qaytaradigan mock amalga oshirish bilan almashtiriladi. Async-await kodni yopilishlar va delegate'larsiz sinxron va o'qilishi oson qiladi. Combine reaktivligi uchun Repository metodlari async throws o'rniga AnyPublisher qaytaradi.
Android amalga oshirishi Repository asinxron ish uchun Kotlin Coroutines va Flow'dan keng foydalanadi. Google Repository'ni Android arxitekturasi bo'yicha rasmiy qo'llanmada (Android Architecture Components) tavsiya qiladi. Repository konstruktor orqali RemoteDataSource (Retrofit) va LocalDataSource (Room) ni qabul qiladi, ViewModel esa Repository'dan Flow'ga obuna bo'ladi. Repository ma'lumot strategiyasini boshqaradi: avval kesh, keyin tarmoq yoki har doim tarmoq keshga yozish bilan.
interface UserRepository {
fun getUsers(): Flow<Result<List<User>>>
}
interface UserRemoteDataSource {
suspend fun fetchUsers(): List<User>
}
interface UserLocalDataSource {
fun getCachedUsers(): Flow<List<User>>
suspend fun saveUsers(users: List<User>)
}
class UserRepositoryImpl(
private val remote: UserRemoteDataSource,
private val local: UserLocalDataSource
) : UserRepository {
override fun getUsers(): Flow<Result<List<User>>> = flow {
emit(Result.Loading)
local.getCachedUsers().collect { cached ->
if (cached.isNotEmpty()) {
emit(Result.Success(cached))
}
}
try {
val users = remote.fetchUsers()
local.saveUsers(users)
emit(Result.Success(users))
} catch (e: Exception) {
emit(Result.Error(e))
}
}
}
Result o'rami yuqoridagi misolda Android uchun standartdir: sealed class Result ViewModel'ga yuklash holati (Loading, Success, Error) haqida xabar beradi. ViewModel collect orqali obuna bo'ladi va StateFlow yoki LiveData'ni yangilaydi. Repository Flow bilan avtomatik ravishda UI'ni ma'lumotlar bazasidagi o'zgarishlar haqida xabardor qiladi — bu UI qo'lda yangilashsiz o'zgarishlardan xabarsiz qoladigan bir martalik so'rovlardan asosiy farqdir.
DataSource — muayyan ma'lumot manbai bilan ishlash uchun mas'ul bo'lgan sinflar. RemoteDataSource API'dan ma'lumot olish uchun HTTP-klientdan (URLSession, Retrofit, Ktor) foydalanadi. LocalDataSource mahalliy saqlash bilan (CoreData, Realm, Room, UserDefaults, DataStore) ishlaydi. Har bir DataSource tor mas'uliyatga ega: RemoteDataSource faqat API so'rov formatini biladi, LocalDataSource — ma'lumotlar bazasi sxemasini. Repository ularni birlashtirib, keshlash strategiyasini amalga oshiradi.
| DataSource | iOS Platformasi | Android Platformasi | Manba |
|---|---|---|---|
| Remote | URLSession + Codable | Retrofit + Moshi/Gson | REST / GraphQL API |
| Local (MB) | CoreData, SwiftData | Room, SQLDelight | Qurilmadagi SQLite |
| Local (kesh) | NSCache, UserDefaults | DataStore, EncryptedSP | Xotirada / disk |
| Preferensiya | UserDefaults, Keychain | SharedPreferences, EncryptedSP | Sozlamalar, tokenlar |
Keshlash strategiyalari Repository'da: Cache-First (avval kesh, keyin fon yuklash), Network-Only (faqat tarmoq, to'lov ekranlari uchun), Network-First-With-Cache-Backup (avval tarmoq, xato bo'lsa — kesh). Strategiya tanlovi ssenariyga bog'liq: mamlakatlar ro'yxatini uzoq muddat keshlash mumkin, valyuta kurslarini — 15 daqiqa, hamyon balansini — faqat tarmoqdan. Repository strategiyani amalga oshiradi va ViewModel yoki UI'ni o'zgartirmasdan uni o'zgartiradi.
Repository va Service — bir-biriga o'xshash funksiyalarga ega turli naqshlar. Repository ma'lumotlarga kirish va ularni keshlash uchun javobgar bo'lib, ma'lumot modellarini qaytaradi. Service (yoki Interactor, Use Case) biznes mantiqni o'z ichiga oladi: validatsiya, ma'lumot transformatsiyasi, bir nechta Repository chaqiruvlarini orkestratsiya qilish. Service buyurtmani rasmiylashtirish uchun UserRepository, OrderRepository va NotificationRepository'ni birlashtirishi mumkin. Repository biznes mantiqni o'z ichiga olmaydi — faqat CRUD va keshlash.
Repository qachon tanlanadi — ko'p manbali ma'lumot navigatsiyasi (API + MB + kesh), offline-first arxitekturasi, keshlash va manbalarni shaffof almashtirish zarurati. Repository Clean Architecture'da majburiy va Google tomonidan Android ilovalari uchun tavsiya etiladi. iOS'da VIPER arxitekturasida Repository rolini Interactor qatlami bajaradi, ma'lumotlarga kirish uchun Manager yoki Service bilan o'zaro aloqada bo'ladi.
Service qachon yetarli — bitta ma'lumot manbai bilan oddiy ilovalar, yozmasdan faqat o'qish ekranlari, offline rejimi bo'lmagan loyihalar. Bunday hollarda DataSource to'g'ridan-to'g'ri ViewModel yoki Presenter tomonidan ishlatiladi, Repository esa ortiqcha qatlamga aylanadi. Biroq, Repository'ni erta bosqichda qo'shish katta xarajat talab qilmaydi va kelajakda keshlash va testlarni qo'shishni osonlashtiradi.
Tez-tez beriladigan savollar
DataSource — bitta manba bilan ishlaydigan sinf (API, MB, kesh). Repository — bir nechta DataSource'ni boshqaradigan va yagona interfeys taqdim etadigan sinf. Repository qaysi DataSource'dan ma'lumot olishni hal qiladi va keshlashni muvofiqlashtiradi. DataSource boshqa manbalarning mavjudligini bilmaydi, Repository har bir manbaning amalga oshirish tafsilotlarini bilmaydi.
Ha, Repository SwiftUI'da ma'lumotlarni View'dan ajratish uchun foydalidir. ViewModel Repository'dan Publisher'ga obuna bo'ladi, Repository esa keshlash va sinxronizatsiyani boshqaradi. Oddiy ilovalarda to'g'ridan-to'g'ri ViewModel'da URLSession ishlatish mumkin, ammo testlash va masshtablash uchun Repository afzalroq. Apple bu naqshni majburlamaydi, lekin u SwiftData va Network.framework bilan mos keladi.
DataSource'lar Dependency Injection orqali mock-ob'ektlar bilan almashtiriladi. Test mock RemoteDataSource (oldindan belgilangan JSON qaytaradi) va mock LocalDataSource (ma'lumotlar saqlanganligini tekshiradi) yaratadi. Repository alohida testlanadi: keshlash strategiyasi, xato boshqaruvi va chaqiruvlarning to'g'ri tartibi tekshiriladi. Integratsiya testlari uchun TestDispatcher (Kotlin) yoki MainActor.run (Swift) ishlatiladi.
Mumkin, lekin tavsiya etilmaydi. Protokolsiz testlarda va preview'da amalga oshirishni almashtirish mumkin emas. Kotlin'da Repository interfeysi DI (Dagger, Hilt, Koin) orqali amalga oshirishni almashtirishga imkon beradi. Swift'da Repository protokoli async-await va Combine kodini testlash uchun majburiydir. Istisno — keshlash mantiqiga ega bo'lmagan, bitta ma'lumot manbai bilan oddiy loyihalar.
Offline-first — ilova internet bo'lmagan holda mahalliy ma'lumotlardan foydalanib ishlaydigan strategiya. Repository asosiy rol o'ynaydi: avval mahalliy DataSource'dan ma'lumotlarni qaytaradi, keyin fonda server bilan sinxronlashadi. Foydalanuvchi ma'lumotlarni darhol ko'radi, Repository esa tarmoqdan yuklagandan keyin ularni yangilaydi. Room Flow bilan mahalliy ma'lumotlar bazasida o'zgarishlar bo'lganda UI'ni reaktiv yangilashni ta'minlaydi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.