Repository Pattern: Was es ist, das Datenabstraktionsmuster in iOS und Android

Autor: IT Sectr Veröffentlicht: 2026-02-17 Lesezeit: 7 Min.

Repository Pattern — ein Muster, das eine Abstraktionsschicht zwischen der Geschäftslogik und den Datenquellen hinzufügt. Anstatt direkt API, Datenbank oder Cache aufzurufen, bietet das Repository eine einheitliche Schnittstelle zum Abrufen und Speichern von Daten. Dies vereinfacht Tests und das Wechseln zwischen Quellen. Lesen Sie mehr in der Android Data Layer-Dokumentation.

Wichtige Punkte

  • Repository Pattern — eine Schicht zwischen Geschäftslogik und Datenquellen (API, DB, Cache)
  • DataSource — separate Klassen für jede Quelle: RemoteDataSource, LocalDataSource
  • Single Source of Truth — das Repository wird zur einzigen Datenquelle für die UI-Schicht
  • Testen — Repository kann über DI einfach durch ein Mock-Objekt für Unit-Tests ersetzt werden
  • Kompatibilität — funktioniert mit MVVM, Clean Architecture und anderen Architekturmustern

Was ist das Repository Pattern in der mobilen Entwicklung?

Repository Pattern ist ein strukturelles Muster, das die Geschäftslogik vom direkten Zugriff auf Datenquellen isoliert. Anstatt dass eine Activity, UIViewController oder ViewModel direkt Retrofit, URLSession, Room oder CoreData aufruft, kommunizieren sie mit dem Repository. Das Repository entscheidet, woher die Daten kommen — aus dem Netzwerk, der Datenbank oder dem Cache — und gibt das Ergebnis in einem einheitlichen Format zurück. Dies implementiert das Prinzip der einzigen Verantwortung — die UI weiß nicht, wie oder woher die Daten stammen.

Repository-Komponenten umfassen ein Interface (Protokoll), eine Implementierung und eine oder mehrere DataSources. Eine DataSource ist eine Klasse, die mit einer einzigen Quelle arbeitet: RemoteDataSource ruft die API über einen HTTP-Client auf, LocalDataSource liest und schreibt in die Datenbank. Das Repository erhält die DataSources über den Konstruktor (Dependency Injection) und entscheidet, welche Quelle verwendet wird. Bei der Anforderung einer Benutzerliste prüft das Repository beispielsweise zuerst den Cache, dann die Datenbank, dann das Netzwerk.

Vorteile des Repository Pattern: Isolation von Datenquellenänderungen (API-Änderungen, DB-Migrationen) wirkt sich nicht auf die UI-Schicht aus; Unit-Testing durch Ersetzen von Repository oder DataSource; Caching ist für die UI transparent; Wechsel zwischen Online- und Offline-Modi ohne Änderung der Bildschirmlogik. Die Android-Community empfiehlt Repository als obligatorische Schicht in Clean Architecture.

Repository Pattern in iOS mit Swift: Implementierung und Beispiel

iOS-Implementierung des Repository basiert auf Swift-Protokollen. Das Repository-Protokoll deklariert Methoden zum Abrufen und Speichern von Daten. Die tatsächliche Implementierung wird über den Initialisierer injiziert — dies ermöglicht das Ersetzen der Implementierung in Tests und SwiftUI-Vorschauen. DataSources werden ebenfalls als Protokolle deklariert: Protocol RemoteDataSource, Protocol LocalDataSource. ViewModel oder Interactor kennen keine spezifische Implementierung — nur das Repository-Protokoll.

swift
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 in iOS für Repository wird typischerweise über eine Factory oder einen DI-Container (Swinject, Factory) konfiguriert. In Tests wird das UserRepository-Protokoll durch eine Mock-Implementierung ersetzt, die vordefinierte Daten zurückgibt. Async-await macht den Code synchron und lesbar ohne Closures und Delegates. Für Combine-Reaktivität geben Repository-Methoden AnyPublisher statt async throws zurück.

Repository Pattern in Android mit Kotlin: Beispiel mit Flow

Android-Implementierung des Repository verwendet umfassend Kotlin Coroutines und Flow für asynchrone Operationen. Google empfiehlt Repository im offiziellen Android-Architekturleitfaden (Android Architecture Components). Das Repository akzeptiert RemoteDataSource (Retrofit) und LocalDataSource (Room) über den Konstruktor, und das ViewModel abonniert einen Flow vom Repository. Das Repository verwaltet die Datenstrategie: Cache-First, Network-First oder immer Netzwerk mit Cache-Schreiben.

kotlin
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 im obigen Beispiel ist Standard für Android: Eine versiegelte Klasse Result informiert das ViewModel über den Ladezustand (Loading, Success, Error). Das ViewModel abonniert über collect und aktualisiert StateFlow oder LiveData. Repository mit Flow benachrichtigt die UI automatisch über Datenbankänderungen — dies ist ein wichtiger Unterschied zu einmaligen Anfragen, bei denen die UI ohne manuelle Aktualisierung nichts von Änderungen erfährt.

DataSource: Remote, Local und Daten-Caching

DataSource — Klassen, die für die Arbeit mit einer bestimmten Datenquelle verantwortlich sind. RemoteDataSource verwendet einen HTTP-Client (URLSession, Retrofit, Ktor), um Daten von der API abzurufen. LocalDataSource arbeitet mit lokalem Speicher (CoreData, Realm, Room, UserDefaults, DataStore). Jede DataSource hat eine enge Verantwortung: RemoteDataSource kennt nur das API-Anfrageformat, LocalDataSource — das Datenbankschema. Das Repository kombiniert sie und implementiert eine Caching-Strategie.

DataSourceiOS-PlattformAndroid-PlattformQuelle
RemoteURLSession + CodableRetrofit + Moshi/GsonREST / GraphQL API
Local (DB)CoreData, SwiftDataRoom, SQLDelightSQLite auf Gerät
Local (Cache)NSCache, UserDefaultsDataStore, EncryptedSPIn-Memory / Disk
EinstellungenUserDefaults, KeychainSharedPreferences, EncryptedSPEinstellungen, Token

Caching-Strategien im Repository: Cache-First (zuerst Cache, dann Hintergrundladen), Network-Only (nur Netzwerk, für Zahlungsbildschirme), Network-First-With-Cache-Backup (zuerst Netzwerk, bei Fehler Fallback auf Cache). Die Wahl der Strategie hängt vom Szenario ab: Eine Länderliste kann lange gecacht werden, Wechselkurse — für 15 Minuten, Wallet-Guthaben — nur aus dem Netzwerk. Das Repository implementiert die Strategie und ändert sie, ohne ViewModel oder UI zu modifizieren.

Repository Pattern vs Service Layer: Unterschiede und Wahl

Repository und Service sind unterschiedliche Muster mit überlappenden Funktionen. Repository ist für Datenzugriff und Caching verantwortlich und gibt Datenmodelle zurück. Service (oder Interactor, Use Case) enthält Geschäftslogik: Validierung, Datentransformation, Orchestrierung mehrerer Repository-Aufrufe. Service kann UserRepository, OrderRepository und NotificationRepository kombinieren, um eine Bestellung zu verarbeiten. Repository enthält keine Geschäftslogik — nur CRUD und Caching.

Wann Repository wählen — Datennavigation mit mehreren Quellen (API + DB + Cache), Offline-First-Architektur, Notwendigkeit von Caching und transparentem Quellenwechsel. Repository ist in Clean Architecture obligatorisch und wird von Google für Android-Anwendungen empfohlen. In der VIPER-Architektur unter iOS übernimmt die Interactor-Schicht die Rolle des Repository und interagiert mit Manager oder Service für den Datenzugriff.

Wann Service ausreicht — einfache Anwendungen mit einer einzigen Datenquelle, Nur-Lese-Bildschirme ohne Schreibzugriff, Projekte ohne Offline-Modus. In solchen Fällen wird DataSource direkt von ViewModel oder Presenter verwendet, und Repository wird zu einer überflüssigen Schicht. Das frühzeitige Hinzufügen von Repository erfordert jedoch keinen großen Aufwand und vereinfacht das spätere Hinzufügen von Caching und Tests.

Häufig gestellte Fragen

Wie unterscheidet sich Repository von DataSource?

DataSource ist eine Klasse, die mit einer einzigen Quelle arbeitet (API, DB, Cache). Repository ist eine Klasse, die mehrere DataSources verwaltet und eine einheitliche Schnittstelle bereitstellt. Das Repository entscheidet, welche DataSource verwendet wird, und koordiniert das Caching. DataSource weiß nichts von der Existenz anderer Quellen; Repository kennt keine Implementierungsdetails jeder Quelle.

Ist Repository in iOS mit SwiftUI notwendig?

Ja, Repository ist in SwiftUI nützlich, um Daten von der View zu trennen. Das ViewModel abonniert einen Publisher aus dem Repository, und das Repository verwaltet Caching und Synchronisation. In einfachen Anwendungen kann URLSession direkt im ViewModel verwendet werden, aber für Testbarkeit und Skalierbarkeit ist Repository vorzuziehen. Apple erzwingt das Muster nicht, aber es ist kompatibel mit SwiftData und Network.framework.

Wie testet man Repository mit mehreren DataSources?

DataSources werden über Dependency Injection durch Mock-Objekte ersetzt. Der Test erstellt eine Mock-RemoteDataSource (gibt vordefiniertes JSON zurück) und eine Mock-LocalDataSource (prüft, ob Daten gespeichert wurden). Das Repository wird isoliert getestet: Caching-Strategie, Fehlerbehandlung und korrekte Aufrufreihenfolge werden überprüft. Für Integrationstests werden TestDispatcher (Kotlin) oder MainActor.run (Swift) verwendet.

Kann Repository ohne Interface (Protokoll) verwendet werden?

Möglich, aber nicht empfohlen. Ohne Protokoll ist es unmöglich, die Implementierung in Tests und Vorschauen zu ersetzen. In Kotlin ermöglicht das Repository-Interface das Ersetzen der Implementierung über DI (Dagger, Hilt, Koin). In Swift ist das Repository-Protokoll für das Testen von async-await- und Combine-Code obligatorisch. Ausnahme sind einfache Projekte mit einer einzigen Datenquelle, bei denen Repository keine Caching-Logik enthält.

Was ist Offline-First im Kontext von Repository?

Offline-First ist eine Strategie, bei der die Anwendung ohne Internet mit lokalen Daten arbeitet. Repository spielt eine Schlüsselrolle: Es gibt zuerst Daten aus der lokalen DataSource zurück und synchronisiert dann im Hintergrund mit dem Server. Der Benutzer sieht die Daten sofort, und das Repository aktualisiert sie nach dem Laden aus dem Netzwerk. Room mit Flow bietet reaktive UI-Updates bei Datenänderungen in der lokalen Datenbank.

Zusammenfassung

  • Repository Pattern — eine Abstraktionsschicht zwischen UI und Datenquellen
  • DataSource — separate Klassen für API, DB und Cache
  • Protokolle — erforderlich für Tests und Austausch von Implementierungen
  • Caching-Strategien — Cache-First, Network-Only, Network-First-With-Cache-Backup
  • iOS — async-await oder Combine mit Protokollen
  • Android — Kotlin Flow + Room + Retrofit, von Google empfohlener Ansatz
  • Testen — Mock-DataSources via DI, Überprüfung von Caching-Strategien

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch