Repository Pattern — एक पैटर्न जो बिज़नेस लॉजिक और डेटा स्रोतों के बीच एब्स्ट्रैक्शन लेयर जोड़ता है। API, डेटाबेस या कैश को सीधे कॉल करने के बजाय, Repository डेटा प्राप्त करने और संग्रहीत करने के लिए एक समान इंटरफ़ेस प्रदान करता है। यह परीक्षण और स्रोतों के बीच स्विच करना सरल बनाता है। अधिक जानकारी के लिए Android Data Layer दस्तावेज़ीकरण देखें।
मुख्य बिंदु
Repository Pattern एक संरचनात्मक पैटर्न है जो बिज़नेस लॉजिक को डेटा स्रोतों तक सीधी पहुँच से अलग करता है। Activity, UIViewController या ViewModel द्वारा सीधे Retrofit, URLSession, Room या CoreData को कॉल करने के बजाय, वे Repository के साथ संचार करते हैं। Repository तय करता है कि डेटा कहाँ से लेना है — नेटवर्क, डेटाबेस या कैश — और परिणाम एक समान प्रारूप में लौटाता है। यह एकल जिम्मेदारी सिद्धांत को लागू करता है — UI को यह नहीं पता होता कि डेटा कैसे या कहाँ से प्राप्त हुआ।
Repository घटक में एक इंटरफ़ेस (प्रोटोकॉल), एक कार्यान्वयन और एक या अधिक DataSources शामिल हैं। DataSource एक क्लास है जो एकल स्रोत के साथ काम करता है: RemoteDataSource HTTP क्लाइंट के माध्यम से API को कॉल करता है, LocalDataSource डेटाबेस में पढ़ता और लिखता है। Repository कंस्ट्रक्टर के माध्यम से DataSources प्राप्त करता है (डिपेंडेंसी इंजेक्शन) और तय करता है कि किस स्रोत का उपयोग करना है। उदाहरण के लिए, उपयोगकर्ताओं की सूची का अनुरोध करते समय, Repository पहले कैश, फिर डेटाबेस, फिर नेटवर्क की जाँच करता है।
Repository Pattern के लाभ: डेटा स्रोतों में बदलाव (API परिवर्तन, DB माइग्रेशन) का UI लेयर पर कोई प्रभाव नहीं पड़ता; Repository या DataSource को बदलकर यूनिट टेस्टिंग; UI के लिए कैशिंग पारदर्शी है; स्क्रीन लॉजिक को बदले बिना ऑनलाइन और ऑफलाइन मोड के बीच स्विच करना। Android समुदाय Clean Architecture में Repository को अनिवार्य लेयर के रूप में अनुशंसित करता है।
iOS कार्यान्वयन Repository Swift प्रोटोकॉल पर बनाया गया है। Repository प्रोटोकॉल डेटा प्राप्त करने और संग्रहीत करने के तरीके घोषित करता है। वास्तविक कार्यान्वयन इनिशियलाइज़र के माध्यम से इंजेक्ट किया जाता है — यह परीक्षणों और SwiftUI पूर्वावलोकन में कार्यान्वयन को बदलने की अनुमति देता है। DataSources को भी प्रोटोकॉल के रूप में घोषित किया जाता है: Protocol RemoteDataSource, Protocol LocalDataSource। ViewModel या Interactor किसी विशिष्ट कार्यान्वयन के बारे में नहीं जानता — केवल 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
}
}
डिपेंडेंसी इंजेक्शन iOS में Repository के लिए आमतौर पर फ़ैक्टरी या DI कंटेनर (Swinject, Factory) के माध्यम से कॉन्फ़िगर किया जाता है। परीक्षणों में, UserRepository प्रोटोकॉल को मॉक कार्यान्वयन से बदल दिया जाता है जो पूर्वनिर्धारित डेटा लौटाता है। Async-await कोड को closures और delegates के बिना सिंक्रोनस और पढ़ने योग्य बनाता है। Combine रिएक्टिविटी के लिए, Repository विधियाँ async throws के बजाय AnyPublisher लौटाती हैं।
Android कार्यान्वयन Repository एसिंक्रोनस संचालन के लिए Kotlin Coroutines और Flow का व्यापक उपयोग करता है। Google आधिकारिक Android आर्किटेक्चर गाइड (Android Architecture Components) में Repository की अनुशंसा करता है। Repository कंस्ट्रक्टर के माध्यम से RemoteDataSource (Retrofit) और LocalDataSource (Room) स्वीकार करता है, और ViewModel Repository से Flow में सब्सक्राइब करता है। Repository डेटा रणनीति प्रबंधित करता है: पहले कैश, पहले नेटवर्क, या हमेशा नेटवर्क के साथ कैश राइट।
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 रैपर ऊपर दिए गए उदाहरण में Android के लिए मानक है: एक सीलबंद क्लास Result ViewModel को लोडिंग स्थिति (लोड हो रहा है, सफलता, त्रुटि) के बारे में सूचित करता है। ViewModel collect के माध्यम से सब्सक्राइब करता है और StateFlow या LiveData को अपडेट करता है। Repository Flow के साथ स्वचालित रूप से UI को डेटाबेस परिवर्तनों के बारे में सूचित करता है — यह एकल अनुरोधों से मुख्य अंतर है जहाँ UI मैन्युअल रिफ्रेश के बिना परिवर्तनों के बारे में नहीं जानता।
DataSource — क्लासेस जो एक विशिष्ट डेटा स्रोत के साथ काम करने के लिए जिम्मेदार हैं। RemoteDataSource API से डेटा प्राप्त करने के लिए HTTP क्लाइंट (URLSession, Retrofit, Ktor) का उपयोग करता है। LocalDataSource स्थानीय स्टोरेज (CoreData, Realm, Room, UserDefaults, DataStore) के साथ काम करता है। प्रत्येक DataSource की एक संकीर्ण जिम्मेदारी होती है: RemoteDataSource केवल API अनुरोध प्रारूप के बारे में जानता है, LocalDataSource — डेटाबेस स्कीमा के बारे में। Repository उन्हें जोड़ता है, कैशिंग रणनीति लागू करता है।
| DataSource | iOS प्लेटफ़ॉर्म | Android प्लेटफ़ॉर्म | स्रोत |
|---|---|---|---|
| Remote | URLSession + Codable | Retrofit + Moshi/Gson | REST / GraphQL API |
| Local (DB) | CoreData, SwiftData | Room, SQLDelight | डिवाइस पर SQLite |
| Local (कैश) | NSCache, UserDefaults | DataStore, EncryptedSP | इन-मेमोरी / डिस्क |
| प्राथमिकताएँ | UserDefaults, Keychain | SharedPreferences, EncryptedSP | सेटिंग्स, टोकन |
Repository में कैशिंग रणनीतियाँ: Cache-First (पहले कैश, फिर बैकग्राउंड लोड), Network-Only (केवल नेटवर्क, भुगतान स्क्रीन के लिए), Network-First-With-Cache-Backup (पहले नेटवर्क, त्रुटि पर कैश से बैकअप)। रणनीति का चयन परिदृश्य पर निर्भर करता है: देशों की सूची को लंबे समय तक कैश किया जा सकता है, मुद्रा दरें — 15 मिनट के लिए, वॉलेट बैलेंस — केवल नेटवर्क से। Repository रणनीति लागू करता है और ViewModel या UI को बदले बिना इसे बदलता है।
Repository और Service अलग-अलग पैटर्न हैं जिनके कार्य ओवरलैप होते हैं। Repository डेटा एक्सेस और कैशिंग के लिए जिम्मेदार है, डेटा मॉडल लौटाता है। Service (या Interactor, Use Case) में बिज़नेस लॉजिक होता है: सत्यापन, डेटा ट्रांसफ़ॉर्मेशन, कई Repository कॉल का ऑर्केस्ट्रेशन। Service ऑर्डर प्रोसेस करने के लिए UserRepository, OrderRepository और NotificationRepository को जोड़ सकता है। Repository में बिज़नेस लॉजिक नहीं होता — केवल CRUD और कैशिंग।
Repository कब चुनें — कई स्रोतों (API + DB + कैश) के साथ डेटा नेविगेशन, ऑफलाइन-फ़र्स्ट आर्किटेक्चर, कैशिंग और पारदर्शी स्रोत स्विचिंग की आवश्यकता। Clean Architecture में Repository अनिवार्य है और Google द्वारा Android एप्लिकेशन के लिए अनुशंसित है। iOS पर VIPER आर्किटेक्चर में, Repository की भूमिका Interactor लेयर निभाती है, जो डेटा एक्सेस के लिए Manager या Service के साथ इंटरैक्ट करती है।
Service कब पर्याप्त है — एकल डेटा स्रोत वाले सरल एप्लिकेशन, बिना लेखन के केवल-पढ़ने वाली स्क्रीन, ऑफलाइन मोड के बिना प्रोजेक्ट। ऐसे मामलों में, DataSource का उपयोग सीधे ViewModel या Presenter द्वारा किया जाता है, और Repository एक अनावश्यक लेयर बन जाता है। हालाँकि, शुरुआती चरण में Repository जोड़ने में अधिक प्रयास नहीं लगता और भविष्य में कैशिंग और टेस्ट जोड़ना सरल बनाता है।
अक्सर पूछे जाने वाले प्रश्न
DataSource एक क्लास है जो एकल स्रोत (API, DB, कैश) के साथ काम करता है। Repository एक क्लास है जो कई DataSources का प्रबंधन करता है और एक समान इंटरफ़ेस प्रदान करता है। Repository तय करता है कि किस DataSource का उपयोग करना है और कैशिंग का समन्वय करता है। DataSource को अन्य स्रोतों के अस्तित्व के बारे में पता नहीं होता; Repository को प्रत्येक स्रोत के कार्यान्वयन विवरण के बारे में पता नहीं होता।
हाँ, Repository SwiftUI में डेटा को View से अलग करने के लिए उपयोगी है। ViewModel Repository से Publisher में सब्सक्राइब करता है, और Repository कैशिंग और सिंक्रोनाइज़ेशन प्रबंधित करता है। सरल एप्लिकेशन में, ViewModel में सीधे URLSession का उपयोग किया जा सकता है, लेकिन परीक्षण क्षमता और स्केलेबिलिटी के लिए Repository बेहतर है। Apple पैटर्न को लागू नहीं करता, लेकिन यह SwiftData और Network.framework के साथ संगत है।
डिपेंडेंसी इंजेक्शन के माध्यम से DataSources को मॉक ऑब्जेक्ट से बदला जाता है। परीक्षण एक मॉक RemoteDataSource (पूर्वनिर्धारित JSON लौटाता है) और एक मॉक LocalDataSource (सत्यापित करता है कि डेटा सहेजा गया है) बनाता है। Repository को अलग-थलग करके परीक्षण किया जाता है: कैशिंग रणनीति, त्रुटि प्रबंधन और सही कॉल क्रम सत्यापित किया जाता है। एकीकरण परीक्षण के लिए TestDispatcher (Kotlin) या MainActor.run (Swift) का उपयोग किया जाता है।
संभव है लेकिन अनुशंसित नहीं। प्रोटोकॉल के बिना, परीक्षणों और पूर्वावलोकन में कार्यान्वयन को बदलना असंभव है। Kotlin में, Repository इंटरफ़ेस DI (Dagger, Hilt, Koin) के माध्यम से कार्यान्वयन को बदलने की अनुमति देता है। Swift में, async-await और Combine कोड के परीक्षण के लिए Repository प्रोटोकॉल अनिवार्य है। अपवाद सरल प्रोजेक्ट हैं जिनमें एकल डेटा स्रोत होता है जहाँ Repository में कैशिंग लॉजिक नहीं होता।
Offline-first एक रणनीति है जहाँ एप्लिकेशन स्थानीय डेटा का उपयोग करके इंटरनेट के बिना काम करता है। Repository महत्वपूर्ण भूमिका निभाता है: यह पहले स्थानीय DataSource से डेटा लौटाता है, फिर बैकग्राउंड में सर्वर से सिंक्रोनाइज़ करता है। उपयोगकर्ता तुरंत डेटा देखता है, और Repository नेटवर्क से लोड करने के बाद इसे अपडेट करता है। Room Flow के साथ स्थानीय डेटाबेस में डेटा बदलने पर रिएक्टिव UI अपडेट प्रदान करता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें