Domain-Driven Design in Java: nicht nur Theorie, sondern lebendiger Code

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum DDD kein modischer Begriff, sondern ein Werkzeug zur Projektrettung ist



Jeder Java-Entwickler kennt die Situation: Der Code funktioniert, die Geschäftslogik ist über die Services verteilt, und nach einem halben Jahr kann nur noch der Autor (und das mit Mühe) das Projekt verstehen. Kommt Ihnen das bekannt vor? Das ist das klassische anemic domain model – wenn Entitäten nur POJOs mit Gettern und Settern sind und die gesamte Logik in „dicken“ Services lebt.



Hier kommt Domain-Driven Design (DDD) ins Spiel – ein Ansatz, der die Geschäftslogik und nicht die technischen Details in den Mittelpunkt der Entwicklung stellt. Und nein, das ist keine weitere „theoretische“ Methodik. DDD in Java-Projekten liefert konkrete Patterns, die Chaos in eine saubere, wartbare Architektur verwandeln. In diesem Artikel analysieren wir DDD in der Praxis: mit Code, Beispielen und ohne unnötige Theorie.



Strategisches vs. Taktisches DDD: Was für ein Java-Projekt wählen?



DDD unterteilt sich in zwei Ebenen: strategisch und taktisch. Ersteres hilft, ein großes System in Bounded Contexts (Kontexte) zu unterteilen und die Kommunikation zwischen ihnen zu gestalten. Letzteres liefert konkrete Bausteine für den Code: Entity, Value Object, Aggregate, Repository, Domain Event usw.



Für einen Java-Entwickler ist taktisches DDD der richtige Einstiegspunkt. Es bietet Werkzeuge, die Sie bereits heute anwenden können. Aber ohne ein strategisches Verständnis der Kontexte riskieren Sie, ein „universelles“ Modell zu erstellen, das niemandem gerecht wird. Beginnen wir daher klein: Wir analysieren die wichtigsten Patterns am Beispiel einer einfachen, aber realen Domäne – einem Auftragsverwaltungssystem.



Die Bausteine von DDD in Java: Von Entity bis Aggregate



1. Entity – Jede hat ihre eigene Identität



In DDD ist eine Entity ein Objekt, das eine eindeutige Kennung und eine kontinuierliche Lebenslinie besitzt. Sie können alle seine Felder ändern, aber es bleibt dieselbe Entität. In Java ist dies nicht nur ein POJO – es ist ein Objekt mit Verhalten.



Beispiel: Eine Bestellung in einem Online-Shop. Selbst wenn sich der Bestellstatus ändert, ist es immer noch dieselbe Bestellung mit derselben ID.



public class Order {    private final OrderId id; // Value Object, kein primitiver Typ    private OrderStatus status;    private List<OrderLineItem> items;    private Money totalAmount;

public Order(OrderId id) { this.id = id; this.status = OrderStatus.PENDING; this.items = new ArrayList<>(); this.totalAmount = Money.ZERO; }

public void addItem(Product product, int quantity) { // Geschäftsregel: Einem bestätigten Auftrag können keine Artikel hinzugefügt werden if (this.status != OrderStatus.PENDING) { throw new IllegalStateException("Cannot add items to a non-pending order"); } OrderLineItem item = new OrderLineItem(product, quantity); items.add(item); recalculateTotal(); }

public void confirm() { if (items.isEmpty()) { throw new IllegalStateException("Cannot confirm an empty order"); } this.status = OrderStatus.CONFIRMED; // Hier könnte ein Domain-Event ausgelöst werden // registerEvent(new OrderConfirmedEvent(this.id)); }

private void recalculateTotal() { this.totalAmount = items.stream() .map(OrderLineItem::getSubtotal) .reduce(Money.ZERO, Money::add); }

// Getter – nur lesend, keine Setter! public OrderId getId() { return id; } public OrderStatus getStatus() { return status; } public List<OrderLineItem> getItems() { return Collections.unmodifiableList(items); } public Money getTotalAmount() { return totalAmount; }}


Beachten Sie: OrderId ist kein Long, sondern ein Value Object. Warum? Weil ein primitiver Typ keine Semantik trägt. OrderId kann ein Präfix, ein Erstellungsdatum oder eine Pr

Blogs

Buchempfehlungen