Implementing Domain-Driven Design Patterns

1. Implementing Value Objects

TraitDetail
IdentityBy value
ImmutabilityRequired
Self-validationConstructor enforces invariants
Side-effect freeMethods return new instances

Example: Email value object

public record Email(String value) {
    public Email {
        Objects.requireNonNull(value);
        if (!value.matches("^[^@]+@[^@]+\\.[^@]+$")) throw new IllegalArgumentException();
        value = value.toLowerCase(Locale.ROOT);
    }
}

2. Implementing Entities

AspectImplementation
ID typeStrongly typed (e.g., OrderId)
equalsBy ID only
BehaviorMethods enforce invariants
SettersAvoid; use intent methods

3. Implementing Aggregates

RuleDetail
Cluster of entitiesTreated as unit
Single entryAggregate root
Tx boundaryOne aggregate per transaction
Cross-aggregateReference by ID, not object

4. Implementing Aggregate Roots

Example: Root enforces invariants

public class Order {  // aggregate root
    private final OrderId id;
    private final List<OrderLine> lines = new ArrayList<>();
    public void addLine(ProductId p, int qty) {
        if (lines.size() >= 100) throw new IllegalStateException("max 100 lines");
        lines.add(new OrderLine(p, qty));
    }
    public List<OrderLine> lines() { return List.copyOf(lines); }
}

5. Implementing Domain Services

WhenWhy
Behavior spans aggregatesNo natural home
StatelessPure domain operation
Domain languageNamed after business concept

Example: Pricing domain service

public class PricingService {
    public Money price(Order o, Customer c, DiscountPolicy p) {
        return p.apply(o, c);
    }
}

6. Implementing Domain Events

TraitDetail
Past tenseOrderPlaced, PaymentCaptured
ImmutableRecord what happened
Carry minimal dataIDs + essential context
Published by aggregateCollected and dispatched after commit

7. Designing Rich Domain Models

Rich Model

  • Behavior on entities
  • Invariants enforced inside
  • Services orchestrate, not decide

Anemic Model

  • Getters/setters only
  • Logic in services
  • Procedural code

8. Understanding Anemic vs Rich Domain Models

AspectAnemicRich
Where logic livesServicesEntities/aggregates
EncapsulationWeakStrong
Test focusService testsEntity unit tests

9. Defining Bounded Contexts

ElementPurpose
BoundaryExplicit model scope
Ubiquitous languageWithin context only
Context mapRelations between contexts
IntegrationACL, conformist, partner, shared kernel

10. Modeling Business Rules

Rule TypeImplementation
InvariantEnforced in constructor / mutator
PolicyStrategy injected
SpecificationComposable predicate
WorkflowState machine / saga

11. Designing Entity Relationships

RelationshipModeling
Within aggregateDirect object reference
Across aggregatesReference by ID
BidirectionalAvoid unless required
CardinalityDocument explicitly (1:1, 1:N, M:N)

12. Implementing Factories for Aggregates

Example: Aggregate factory

public class OrderFactory {
    public Order create(CustomerId c, List<CartItem> items, IdGenerator idGen) {
        var order = new Order(new OrderId(idGen.next()), c);
        items.forEach(i -> order.addLine(i.productId(), i.qty()));
        return order;
    }
}