Menu
Coddy logo textTech

Wzorzec repozytorium

Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 100 z 110.

Wzorzec repozytorium oddziela logikę dostępu do danych od logiki biznesowej, tworząc warstwę abstrakcji między aplikacją a źródłami danych. Zamiast bezpośrednio komunikować się z bazami danych, interfejsami API lub plikami, klasy współpracują z repozytorium, które obsługuje wszystkie operacje na danych.

Wzorzec definiuje interfejs operacji na danych, a konkretne implementacje obsługują rzeczywisty mechanizm przechowywania. Dzięki temu można łatwo zmieniać źródła danych bez modyfikowania logiki biznesowej:

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

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

// Implementacja w pamięci
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
}

Twoja logika biznesowa zależy wyłącznie od interfejsu UserRepository. Później możesz utworzyć DatabaseUserRepository lub ApiUserRepository, które implementują ten sam interfejs, i zamienić implementacje bez modyfikowania żadnego kodu korzystającego z repozytorium. Ten wzorzec jest niezbędny w aplikacjach, które można testować i łatwo utrzymywać, a których źródła danych mogą się zmieniać z upływem czasu.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system ewidencji produktów z użyciem wzorca Repository! Utworzysz warstwę abstrakcji, która oddzieli sposób przechowywania produktów od sposobu ich używania, dzięki czemu będzie można łatwo zamieniać implementacje magazynowania bez zmieniania logiki biznesowej.

Podzielisz swój kod na dwa pliki:

  • product_repository.dart: Ten plik zawiera klasy encji i repozytorium. Zacznij od klasy Product z polami final dla id (int), name (String) i price (double). Następnie zdefiniuj klasę abstrakcyjną ProductRepository, która deklaruje kontrakt operacji na danych: getById(int id) zwracającą wartość Product dopuszczającą null, getAll() zwracającą listę produktów, save(Product product) do przechowywania produktu oraz delete(int id) do usuwania produktu. Na koniec utwórz InMemoryProductRepository, która implementuje ten interfejs, używając Map<int, Product> do przechowywania danych.
  • main.dart: Zaimportuj plik repozytorium i pokaż wzorzec Repository w działaniu. Utwórz InMemoryProductRepository, ale przechowaj ją w zmiennej typu ProductRepository — dzięki temu pokażesz, że kod zależy od interfejsu, a nie od implementacji. Zapisz trzy produkty: Laptop (id: 1, price: 999.99), Mouse (id: 2, price: 29.99) i Keyboard (id: 3, price: 79.99). Następnie pobierz i wyświetl produkt o id 2 w formacie Found: [name] - $[price]. Usuń produkt o id 1. Na koniec wyświetl liczbę pozostałych produktów jako Products in stock: [count].

Siła tego wzorca polega na tym, że główny kod zna tylko interfejs ProductRepository. Później możesz utworzyć DatabaseProductRepository lub ApiProductRepository i podmienić repozytorium bez zmieniania logiki biznesowej!

Oczekiwany wynik:

Found: Mouse - $29.99
Products in stock: 2

Spróbuj swoich sił

import 'product_repository.dart';

void main() {
  // Utwórz repozytorium — zwróć uwagę, że typem jest interfejs, a nie implementacja
  // TODO: Utwórz InMemoryProductRepository i przypisz je do zmiennej typu ProductRepository
  
  // TODO: Zapisz trzy produkty:
  // - Laptop (id: 1, price: 999.99)
  // - Mouse (id: 2, price: 29.99)
  // - Keyboard (id: 3, price: 79.99)
  
  // TODO: Pobierz produkt o id 2 i wypisz: "Found: [name] - $[price]"
  
  // TODO: Usuń produkt o id 1
  
  // TODO: Wypisz liczbę pozostałych produktów: "Products in stock: [count]"
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Dart online