Repository Pattern — isang pattern na nagdaragdag ng layer ng abstraksiyon sa pagitan ng lohika ng negosyo at mga mapagkukunan ng data. Sa halip na direktang tawag sa API, database, o cache, ang Repository ay nagbibigay ng pinag-isang interface para sa pagkuha at pag-save ng data. Pinapasimple nito ang pagsubok at paglipat sa pagitan ng mga mapagkukunan. Higit pa sa dokumentasyon ng Android Data Layer.
Mga Pangunahing Punto
Repository Pattern — isang pattern ng estruktura na naghihiwalay ng lohika ng negosyo mula sa direktang access sa mga mapagkukunan ng data. Sa halip na Activity, UIViewController, o ViewModel ay direktang tumawag sa Retrofit, URLSession, Room, o CoreData, lumalapit sila sa Repository. Nagpapasya ang Repository kung saan kukuha ng data: mula sa network, database, o cache, at ibinabalik ang resulta sa pinag-isang format. Ito ay implementasyon ng prinsipyo ng iisang responsibilidad — hindi alam ng UI kung paano at saan nakuha ang data.
Mga Bahagi ng Repository ay kinabibilangan ng interface (protocol), implementasyon, at isa o higit pang DataSource. DataSource — isang klase na gumagana sa isang mapagkukunan: RemoteDataSource ay tumatawag sa API sa pamamagitan ng HTTP client, LocalDataSource ay nagbabasa at nagsusulat sa database. Tinatanggap ng Repository ang DataSource sa pamamagitan ng constructor (Dependency Injection) at pinipili kung aling mapagkukunan ang gagamitin. Halimbawa, sa kahilingan para sa listahan ng mga user, unang sinusuri ng Repository ang cache, pagkatapos ang database, pagkatapos ang network.
Mga Bentahe ng Repository Pattern: paghihiwalay ng mga pagbabago sa mapagkukunan ng data (pagbabago ng API, paglipat ng DB) ay hindi nakakaapekto sa UI layer; pagsubok ng unit sa pamamagitan ng pagpapalit ng Repository o DataSource; caching transparent para sa UI; paglipat sa pagitan ng online at offline mode nang hindi binabago ang lohika ng screen. Inirerekomenda ng komunidad ng Android ang Repository bilang sapilitang layer sa Clean Architecture.
Implementasyon sa iOS ng Repository ay binuo sa mga protocol ng Swift. Ang protocol ng Repository ay nagdedeklara ng mga pamamaraan para sa pagkuha at pag-save ng data. Ang aktwal na implementasyon ay ini-inject sa pamamagitan ng initializer — ito ay nagpapahintulot sa pagpapalit ng implementasyon sa mga pagsubok at SwiftUI preview. Ang DataSource ay idinedeklara rin gamit ang mga protocol: Protocol RemoteDataSource, Protocol LocalDataSource. Hindi alam ng ViewModel o Interactor ang konkretong implementasyon — alam lang ang protocol ng Repository.
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 sa iOS para sa Repository ay karaniwang na-configure sa pamamagitan ng factory o DI container (Swinject, Factory). Sa mga pagsubok, ang protocol ng UserRepository ay pinapalitan ng mock implementasyon na nagbabalik ng paunang natukoy na data. Ginagawang synchronous at nababasa ng async-await ang code nang walang mga closure at delegate. Para sa reaktibiti ng Combine, ang mga pamamaraan ng Repository ay nagbabalik ng AnyPublisher sa halip na async throws.
Implementasyon sa Android ng Repository ay malawakang gumagamit ng Kotlin Coroutines at Flow para sa asynchronous na trabaho. Inirerekomenda ng Google ang Repository sa opisyal na gabay sa arkitektura ng Android (Android Architecture Components). Tinatanggap ng Repository ang RemoteDataSource (Retrofit) at LocalDataSource (Room) sa pamamagitan ng constructor, at ang ViewModel ay nag-subscribe sa Flow mula sa Repository. Pinamamahalaan ng Repository ang estratehiya ng data: una cache, pagkatapos network, o palaging network na may pagsulat sa cache.
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 wrapper sa halimbawa sa itaas ay pamantayan para sa Android: sealed class Result ay nagpapaalam sa ViewModel tungkol sa status ng pag-load (Loading, Success, Error). Ang ViewModel ay nag-subscribe sa pamamagitan ng collect at nag-a-update ng StateFlow o LiveData. Ang Repository na may Flow ay awtomatikong nagpapaalam sa UI tungkol sa mga pagbabago sa database — ito ang pangunahing pagkakaiba mula sa isang beses na query kung saan ang UI ay hindi alam ang tungkol sa mga pagbabago nang walang manu-manong pag-refresh.
DataSource — mga klase na responsable sa pagtatrabaho sa isang partikular na mapagkukunan ng data. RemoteDataSource ay gumagamit ng HTTP client (URLSession, Retrofit, Ktor) para kumuha ng data mula sa API. LocalDataSource ay gumagana sa lokal na imbakan (CoreData, Realm, Room, UserDefaults, DataStore). Ang bawat DataSource ay may limitadong responsibilidad: RemoteDataSource ay alam lang ang format ng kahilingan sa API, LocalDataSource — ang schema ng database. Pinagsasama sila ng Repository, na nagpapatupad ng estratehiya sa pag-cache.
| DataSource | Platform ng iOS | Platform ng Android | Mapagkukunan |
|---|---|---|---|
| Remote | URLSession + Codable | Retrofit + Moshi/Gson | REST / GraphQL API |
| Local (DB) | CoreData, SwiftData | Room, SQLDelight | SQLite sa device |
| Local (cache) | NSCache, UserDefaults | DataStore, EncryptedSP | In-memory / disk |
| Preference | UserDefaults, Keychain | SharedPreferences, EncryptedSP | Mga setting, token |
Mga Estratehiya sa Pag-cache sa Repository: Cache-First (una cache, pagkatapos ay background loading), Network-Only (network lang, para sa mga screen ng pagbabayad), Network-First-With-Cache-Backup (una network, kung error — cache). Ang pagpili ng estratehiya ay depende sa senaryo: listahan ng mga bansa ay maaaring i-cache nang matagal, mga rate ng palitan — 15 minuto, balanse ng wallet — mula lamang sa network. Ipinapatupad ng Repository ang estratehiya at binabago ito nang hindi binabago ang ViewModel o UI.
Repository at Service — magkaibang pattern na may magkakapatong na function. Repository ay responsable para sa access sa data at pag-cache nito, nagbabalik ng mga modelo ng data. Service (o Interactor, Use Case) ay naglalaman ng lohika ng negosyo: pag-validate, pagbabago ng data, orkestrasyon ng mga tawag sa maraming Repository. Maaaring pagsamahin ng Service ang UserRepository, OrderRepository, at NotificationRepository para sa pagproseso ng order. Ang Repository ay hindi naglalaman ng lohika ng negosyo — CRUD at pag-cache lamang.
Kailan pumili ng Repository — nabigasyon ng data na may maraming mapagkukunan (API + DB + cache), arkitekturang offline-first, pangangailangan para sa caching at transparent na paglipat sa pagitan ng mga mapagkukunan. Ang Repository ay sapilitan sa Clean Architecture at inirerekomenda ng Google para sa mga Android application. Sa arkitekturang VIPER sa iOS, ang papel ng Repository ay ginagampanan ng Interactor layer, na nakikipag-ugnayan sa Manager o Service para sa access sa data.
Kailan sapat ang Service — simpleng application na may isang mapagkukunan ng data, read-only na screen nang walang pagsulat, mga proyektong walang offline mode. Sa ganitong mga kaso, ang DataSource ay direktang ginagamit ng ViewModel o Presenter, at ang Repository ay nagiging labis na layer. Gayunpaman, ang pagdaragdag ng Repository sa maagang yugto ay hindi nangangailangan ng malaking gastos at pinapadali ang pagdaragdag ng caching at pagsubok sa hinaharap.
Mga Madalas Itanong
DataSource — isang klase na gumagana sa isang mapagkukunan (API, DB, cache). Repository — isang klase na namamahala ng maraming DataSource at nagbibigay ng pinag-isang interface. Nagpapasya ang Repository kung saang DataSource kukuha ng data at nag-coordinate ng caching. Hindi alam ng DataSource ang pagkakaroon ng ibang mga mapagkukunan, hindi alam ng Repository ang mga detalye ng implementasyon ng bawat mapagkukunan.
Oo, kapaki-pakinabang ang Repository sa SwiftUI para sa paghihiwalay ng data mula sa View. Nag-subscribe ang ViewModel sa Publisher mula sa Repository, at pinamamahalaan ng Repository ang caching at pag-sync. Sa simpleng application, maaaring gamitin ang URLSession nang direkta sa ViewModel, ngunit para sa testability at scalability, mas gusto ang Repository. Hindi ipinapatupad ng Apple ang pattern na ito, ngunit ito ay tugma sa SwiftData at Network.framework.
Ang DataSource ay pinapalitan ng mga mock object sa pamamagitan ng Dependency Injection. Gumagawa ang test ng mock RemoteDataSource (nagbabalik ng paunang natukoy na JSON) at mock LocalDataSource (sumusuri kung na-save ang data). Ang Repository ay sinusuri nang izolado: ang estratehiya sa pag-cache, paghawak ng error, at tamang pagkakasunod-sunod ng mga tawag ay sinusuri. Para sa integration test, ginagamit ang TestDispatcher (Kotlin) o MainActor.run (Swift).
Maaari, ngunit hindi inirerekomenda. Kung walang protocol, hindi mapapalitan ang implementasyon sa mga pagsubok at preview. Sa Kotlin, pinapayagan ng interface ng Repository ang pagpapalit ng implementasyon sa pamamagitan ng DI (Dagger, Hilt, Koin). Sa Swift, ang protocol ng Repository ay sapilitan para sa pag-test ng async-await at Combine code. Exception — simpleng proyekto na may isang mapagkukunan ng data kung saan ang Repository ay hindi naglalaman ng lohika ng pag-cache.
Offline-first — isang estratehiya kung saan gumagana ang application nang walang internet gamit ang lokal na data. Ang Repository ay may pangunahing papel: unang nagbabalik ng data mula sa lokal na DataSource, pagkatapos ay nag-sync sa server sa background. Nakikita agad ng user ang data, at ina-update ito ng Repository pagkatapos mag-load mula sa network. Ang Room na may Flow ay nagbibigay ng reaktibong pag-update ng UI kapag nagbago ang data sa lokal na database.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din