Repository Pattern – Strukturierte Datenzugriffe in der Softwarearchitektur

Das Repository Pattern ist ein Architektur- und Entwurfsmuster, das den Zugriff auf Datenquellen abstrahiert und damit eine klare Trennung zwischen Geschäftslogik (Business Logic) und Datenzugriffsschicht (Data Access Layer) ermöglicht.
Es gehört zu den häufig genutzten Mustern in der Anwendungsentwicklung, insbesondere bei Enterprise-Software, Webanwendungen und Microservices.

Das Ziel: Entwickler:innen sollen mit Daten arbeiten, ohne sich um Details wie SQL-Abfragen, Datenbanktreiber oder API-Aufrufe kümmern zu müssen.

Definition des Repository Patterns

Ein Repository fungiert als Schnittstelle zwischen Business-Logik und Datenquelle.
Es verhält sich wie eine virtuelle Sammlung von Objekten, auf die man zugreifen, suchen oder ändern kann, ohne die zugrunde liegende Datenbank oder externe API direkt ansprechen zu müssen.

Wichtige Eigenschaften:

  • Abstraktion: Fachlogik kennt keine Datenbankdetails.

  • Kapselung: SQL, NoSQL oder API-Aufrufe sind im Repository verborgen.

  • Testbarkeit: Business-Logik lässt sich mit Mock-Repositories leichter testen.

Aufbau eines Repository Patterns

Das Repository Pattern besteht typischerweise aus:

  1. Entity / Model

    • Repräsentiert die Datenstruktur (z. B. Kunde, Bestellung, Produkt).

  2. Repository Interface

    • Definiert Methoden für Datenzugriffe (z. B. findById, findAll, save).

  3. Repository Implementation

    • Konkrete Umsetzung der Schnittstelle mit Datenbankzugriff (SQL, ORM, API).

  4. Business Logic Layer

    • Nutzt das Repository, ohne Details der Datenquelle zu kennen.

Vorteile des Repository Patterns

  • Trennung von Logik und Datenzugriff – bessere Wartbarkeit.

  • Einheitliche Schnittstellen – unabhängig von der Datenquelle.

  • Wiederverwendbarkeit – Repositorys können in verschiedenen Services genutzt werden.

  • Testbarkeit – einfacher Einsatz von Mock-Objekten oder In-Memory-Datenbanken.

  • Flexibilität – Wechsel der Datenquelle (z. B. MySQL zu MongoDB) mit wenig Aufwand.

Nachteile des Repository Patterns

  • Mehraufwand: Zusätzliche Abstraktionsschicht erzeugt Boilerplate-Code.

  • Komplexität: Für kleine Projekte oft unnötig.

  • Überabstraktion: Zu viele Repositorys können die Architektur unnötig aufblähen.

Repository Pattern im Vergleich

Muster Beschreibung Typischer Einsatz
Active Record Datenbankzugriff direkt im Model Kleine Projekte, schnelle Prototypen
Data Mapper Separate Mappings zwischen Objekt und Datenbank ORMs (z. B. Doctrine, Hibernate)
Repository Pattern Abstraktion zwischen Logik und Datenquelle Skalierbare Anwendungen, Microservices

Praxisbeispiel

<?php

// =====================
// Entity
// =====================
class Product
{
private ?int $id;
private string $name;

public function __construct(?int $id = null, string $name = „“)
{
$this->id = $id;
$this->name = $name;
}

public function getId(): ?int
{
return $this->id;
}

public function setId(int $id): void
{
$this->id = $id;
}

public function getName(): string
{
return $this->name;
}

public function setName(string $name): void
{
$this->name = $name;
}
}

// =====================
// Repository Interface
// =====================
interface IProductRepository
{
public function findById(int $id): ?Product;
public function findAll(): array;
public function save(Product $product): void;
}

// =====================
// Repository Implementation
// =====================
class ProductRepository implements IProductRepository
{
private \PDO $pdo;

public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}

public function findById(int $id): ?Product
{
$stmt = $this->pdo->prepare(„SELECT id, name FROM products WHERE id = :id“);
$stmt->execute([‚id‘ => $id]);

$row = $stmt->fetch(\PDO::FETCH_ASSOC);

if (!$row) {
return null;
}

return new Product((int)$row[‚id‘], $row[’name‘]);
}

public function findAll(): array
{
$stmt = $this->pdo->query(„SELECT id, name FROM products“);
$products = [];

while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
$products[] = new Product((int)$row[‚id‘], $row[’name‘]);
}

return $products;
}

public function save(Product $product): void
{
if ($product->getId() === null) {
// Insert
$stmt = $this->pdo->prepare(„INSERT INTO products (name) VALUES (:name)“);
$stmt->execute([’name‘ => $product->getName()]);
$product->setId((int)$this->pdo->lastInsertId());
} else {
// Update
$stmt = $this->pdo->prepare(„UPDATE products SET name = :name WHERE id = :id“);
$stmt->execute([
’name‘ => $product->getName(),
‚id‘ => $product->getId()
]);
}
}
}

// =====================
// Business Logic
// =====================
class ProductService
{
private IProductRepository $repository;

public function __construct(IProductRepository $repository)
{
$this->repository = $repository;
}

public function addProduct(string $name): void
{
$product = new Product(null, $name);
$this->repository->save($product);
}
}

// =====================
// Beispiel-Nutzung
// =====================

// Datenbankverbindung
$pdo = new PDO(„mysql:host=localhost;dbname=testdb;charset=utf8“, „root“, „“);

// Repository + Service
$productRepo = new ProductRepository($pdo);
$productService = new ProductService($productRepo);

// Neues Produkt hinzufügen
$productService->addProduct(„Kaffeemaschine“);

// Alle Produkte holen
$allProducts = $productRepo->findAll();
foreach ($allProducts as $p) {
echo $p->getId() . “ – “ . $p->getName() . PHP_EOL;
}

In diesem Beispiel sieht die Business-Logik nur das Repository und muss keine SQL-Abfragen kennen.

Repository Pattern in der Praxis

Das Muster wird oft zusammen mit ORMs (Object-Relational Mappers) wie:

  • Entity Framework (C#)

  • Hibernate (Java)

  • Doctrine (PHP)
    verwendet.

Repositories dienen hier als zusätzliche Abstraktionsschicht über den ORM.

Repository Pattern in Microservices

In modernen Microservice-Architekturen bietet das Repository Pattern zusätzliche Vorteile:

  • Jeder Service kann seine eigene Datenquelle nutzen.

  • Business-Logik bleibt konsistent, unabhängig von SQL, NoSQL oder externen APIs.

  • Erleichtert den Wechsel von Technologien im Lebenszyklus eines Projekts.

Best Practices

  1. Klein und fokussiert halten – Repositorys sollen nur Datenzugriff kapseln.

  2. Interfaces definieren – erleichtert Testbarkeit und Austauschbarkeit.

  3. Nicht zu viele Methoden – lieber Query-Services oder spezialisierte Repositorys.

  4. Zusammenarbeit mit ORMs – Repositories sollten ORM nicht doppeln, sondern ergänzen.

  5. Testing berücksichtigen – Mock-Repositories für Unit-Tests einsetzen.

Kritik am Repository Pattern

Manche Entwickler kritisieren, dass moderne ORMs bereits vieles abdecken, was Repositorys leisten.
Argumente:

  • Doppelung von Abstraktionen – ORM und Repository können redundant wirken.

  • Overengineering – zusätzliche Schicht ohne klaren Mehrwert in kleinen Projekten.

Gleichzeitig bleibt das Pattern in Enterprise-Systemen beliebt, da es eine saubere Architektur und Austauschbarkeit von Datenquellen gewährleistet.

Fazit

Das Repository Pattern ist ein bewährtes Entwurfsmuster, das eine saubere Trennung von Datenzugriff und Geschäftslogik ermöglicht.
Es erleichtert Testbarkeit, Wartbarkeit und Flexibilität von Anwendungen und eignet sich besonders für mittelgroße bis große Projekte sowie Microservices.

Für kleine Projekte kann es jedoch unnötig komplex sein. Hier ist ein direkter ORM-Zugriff oft ausreichend.
Richtig eingesetzt, trägt das Repository Pattern jedoch erheblich zur Qualität und Langlebigkeit von Software bei.