Menu
Coddy logo textTech

Repository-Muster

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 100 von 110.

Das Repository-Pattern trennt die Datenzugriffslogik von der Geschäftslogik, indem es eine Abstraktionsschicht zwischen Ihrer Anwendung und den Datenquellen erstellt. Anstatt Ihre Klassen direkt mit Datenbanken, APIs oder Dateien interagieren zu lassen, arbeiten sie mit einem Repository, das alle Datenoperationen übernimmt.

Das Muster definiert eine Schnittstelle für Datenoperationen, und konkrete Implementierungen übernehmen den eigentlichen Speichermechanismus. Dies macht es einfach, Datenquellen auszutauschen, ohne Ihre Geschäftslogik zu ändern:

// Entität
class User {
  final int id;
  final String name;
  User(this.id, this.name);
}

// Repository-Schnittstelle
abstract class UserRepository {
  User? getById(int id);
  List<User> getAll();
  void save(User user);
  void delete(int id);
}

// In-Memory-Implementierung
class InMemoryUserRepository implements UserRepository {
  final Map<int, User> _users = {};

  @override
  User? getById(int id) => _users[id];

  @override
  List<User> getAll() => _users.values.toList();

  @override
  void save(User user) => _users[user.id] = user;

  @override
  void delete(int id) => _users.remove(id);
}

void main() {
  UserRepository repo = InMemoryUserRepository();
  
  repo.save(User(1, 'Alice'));
  repo.save(User(2, 'Bob'));
  
  print(repo.getById(1)?.name);  // Alice
  print(repo.getAll().length);    // 2
}

Ihre Geschäftslogik hängt nur von der Schnittstelle UserRepository ab. Sie könnten später ein DatabaseUserRepository oder ApiUserRepository erstellen, das dieselbe Schnittstelle implementiert, und die Implementierungen austauschen, ohne den Code zu ändern, der das Repository verwendet. Dieses Muster ist essenziell für testbare, wartbare Anwendungen, bei denen sich Datenquellen im Laufe der Zeit ändern können.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Produktinventarsystem mit dem Repository-Muster! Du erstellst eine Abstraktionsschicht, die die Speicherung von Produkten von ihrer Verwendung trennt. Dadurch lassen sich Speicherimplementierungen einfach austauschen, ohne die Geschäftslogik zu ändern.

Du organisierst deinen Code in zwei Dateien:

  • product_repository.dart: Diese Datei enthält deine Entitäts- und Repository-Klassen. Beginne mit einer Product-Klasse, die final-Felder für id (int), name (String) und price (double) besitzt. Definiere anschließend eine abstrakte Klasse ProductRepository, die den Vertrag für Datenoperationen festlegt: getById(int id), das ein möglicherweise nullbares Product zurückgibt, getAll(), das eine Liste von Produkten zurückgibt, save(Product product) zum Speichern eines Produkts und delete(int id) zum Entfernen eines Produkts. Erstelle schließlich ein InMemoryProductRepository, das diese Schnittstelle mithilfe einer Map<int, Product> zur Speicherung implementiert.
  • main.dart: Importiere deine Repository-Datei und demonstriere das Repository-Muster in Aktion. Erstelle ein InMemoryProductRepository, speichere es aber in einer Variablen vom Typ ProductRepository – so wird deutlich, dass dein Code von der Schnittstelle und nicht von der Implementierung abhängt. Speichere drei Produkte: Laptop (id: 1, price: 999.99), Mouse (id: 2, price: 29.99) und Keyboard (id: 3, price: 79.99). Rufe anschließend das Produkt mit der id 2 ab und gib es im Format Found: [name] - $[price] aus. Lösche das Produkt mit der id 1. Gib zum Schluss die Anzahl der verbleibenden Produkte als Products in stock: [count] aus.

Die Stärke dieses Musters besteht darin, dass dein Hauptcode nur die ProductRepository-Schnittstelle kennt. Du könntest später ein DatabaseProductRepository oder ein ApiProductRepository erstellen und es einbinden, ohne die Geschäftslogik ändern zu müssen!

Erwartete Ausgabe:

Found: Mouse - $29.99
Products in stock: 2

Probier es selbst

import 'product_repository.dart';

void main() {
  // Repository erstellen - beachte, dass der Typ das Interface ist, nicht die Implementierung
  // TODO: Erstelle ein InMemoryProductRepository und speichere es in einer ProductRepository Variable
  
  // TODO: Speichere drei Produkte:
  // - Laptop (id: 1, price: 999.99)
  // - Mouse (id: 2, price: 29.99)
  // - Keyboard (id: 3, price: 79.99)
  
  // TODO: Rufe das Produkt mit id 2 ab und gib es aus: "Found: [name] - $[price]"
  
  // TODO: Lösche das Produkt mit id 1
  
  // TODO: Gib die Anzahl der verbleibenden Produkte aus: "Products in stock: [count]"
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Dart-Compiler