The Repository Pattern
intermediate14 min readLesson 102 of 180
Domain-shaped queries behind an interface, in-memory implementations, and storage as an injected dependency.
The repository pattern
A repository makes persistence look like a collection of domain objects, hiding the storage technology:
public interface ExpenseRepository {
Expense save(Expense e); // insert or update
Optional<Expense> findById(String id);
List<Expense> findAll();
List<Expense> findByCategory(String category);
boolean deleteById(String id);
}
Service code depends on the interface. Production binds a JDBC implementation; tests bind an in-memory one. That is dependency inversion applied to data:
final class InMemoryExpenseRepository implements ExpenseRepository {
private final Map<String, Expense> store = new LinkedHashMap<>();
public Expense save(Expense e) { store.put(e.id(), e); return e; }
public Optional<Expense> findById(String id) { return Optional.ofNullable(store.get(id)); }
...
}
Benefits: services unit-test with zero infrastructure; the storage swap is one constructor argument; queries are named domain operations, not SQL strings leaking everywhere.