DDD
Repositories
Factories
Java
Tactical DDD
Repositories and factories matter because creation and persistence are important boundaries, and the domain should not absorb them casually.
Repositories give the model a persistence-facing boundary. Factories give the model a controlled creation boundary. In DDD, both help keep domain behavior expressive while moving technical concerns to better places.
Why This Topic Matters
Why it matters in real Java systems
When aggregates need to be loaded and saved consistently, and when creation rules are more meaningful than plain constructors, repositories and factories help keep those responsibilities explicit rather than hidden throughout the codebase.
Core Explanation
The main design idea
A repository abstracts access to aggregates as part of the domain model's collaboration. A factory helps create complex domain objects or aggregates in a way that preserves invariants and intent. Neither pattern is unique to DDD, but both become especially important in rich domain models.
The main design question is whether the boundary clarifies the model or merely adds another layer of indirection.
Concept Breakdown
Key ideas to keep in mind
Concept
Repository
A boundary for retrieving and storing aggregates in domain terms.
Concept
Factory
A controlled creation mechanism when construction itself has business meaning or complexity.
Concept
Main payoff
Creation and persistence stop leaking everywhere into use cases and UI code.
Boundary reminder
Boundary reminder
Repository question: does this boundary speak in aggregate language, or is it just a thin database helper? Factory question: is creation complex enough to deserve a named concept, or would a clear constructor be simpler?
Java Example
Java example in the Order Management domain
Java example: repository plus factory
package org.javaomnibus.ecommerce.domain;
public interface OrderRepository {
void save(Order order);
Order requireById(OrderId orderId);
}
public final class OrderFactory {
public Order create(OrderId orderId, CustomerId customerId) {
return new Order(orderId, customerId);
}
}
Code Walkthrough
Step by step
- The repository speaks in terms of Order rather than SQL or HTTP details.
- The factory gives creation a named boundary if creation deserves one.
- This keeps the application layer from scattering persistence and creation concerns everywhere.
- DDD uses these patterns to protect model clarity, not just to add layers.
Real-World Usage
Where this helps in practice
- Aggregate persistence boundaries in domain-heavy applications
- Creation workflows with invariants or multiple required collaborators
- Keeping use cases focused on intent rather than plumbing
Trade-Offs
Trade-offs and when to be careful
- Repositories and factories help when they clarify the model, but they become noise if they are purely ceremonial.
- Factories are especially easy to overuse when constructors would be clearer.
Common Mistakes
Frequent mistakes to watch for
- Creating repositories that expose persistence internals rather than domain concepts
- Using factories for trivial object construction
- Letting repositories become generic data utility layers for unrelated models
- Confusing repository boundaries with direct ORM entity access everywhere
Related Pages
Related concepts
What To Read Next