Architektur- und Entwurfsmuster
Pattern nicht als Theorie, sondern mit Zweck, Einsatzort und Warnsignal.
Enterprise JavaBeispieleArchitekturOffline HTML
Wichtige Muster im Beispielprojekt
| Pattern | Zweck | Einsatzort | Warnsignal |
|---|---|---|---|
| Aggregate Root | Konsistenz innerhalb einer fachlichen Grenze schützen | Order verwaltet Lines und Status | Andere Klassen ändern interne Listen direkt |
| Repository | Persistenz hinter fachlichem Port verstecken | OrderRepository | Domain hängt an EntityManager |
| Application Service | Use Case orchestrieren | PlaceOrderUseCase | Controller enthält Geschäftslogik |
| Ports & Adapters | Frameworks austauschbar halten | Domain/Application vs REST/JPA/Kafka | Adapter rufen andere Adapter direkt auf |
| Factory | Konsistente Erzeugung komplexer Objekte | OrderFactory | new über den ganzen Code verstreut |
| Strategy | Austauschbare Fachvariante | PricingPolicy | if/else-Ketten für Preislogik |
| Policy Object | Autorisierung/Fachregel testbar kapseln | CustomerAccessPolicy | Security-Regeln in Controller verstreut |
| Outbox | DB-Commit und Event zuverlässig verbinden | OutboxMessage | Event nach Commit geht verloren |
| Anti-Corruption Layer | Fremde Modelle fernhalten | SOAP Partner Gateway | WSDL-Klassen in Domain |
Monster-Methode refactoren
Viele Legacy-Systeme enthalten Methoden, die Validierung, Mapping, DB-Zugriff, SOAP-Aufruf, Statusänderung, Logging und Fehlerbehandlung mischen. Refactoring beginnt nicht mit „alles neu“, sondern mit sichtbaren Schnitten.
Refactoring-Ziel: Use Case als lesbare Geschichte
public InvoiceId createInvoice(CreateInvoiceRequest request) {
validate(request);
OrderSnapshot order = orderGateway.load(request.orderId());
Invoice invoice = invoiceFactory.from(order);
invoiceRepository.save(invoice);
outbox.append(InvoiceCreated.from(invoice));
return invoice.id();
}
Prüffrage: Kann ein Fachkollege den Ablauf der Methode erklären, ohne SQL, HTTP oder Frameworkdetails verstehen zu müssen?
Entscheidungsregeln
| Frage | Wenn ja | Wenn nein |
|---|---|---|
| Ist die Regel fachlich stabil? | In Domain/Policy modellieren | In Application/Adapter lassen |
| Ist die Abhängigkeit extern? | Port definieren und Adapter bauen | Direkter Aufruf kann ok sein |
| Muss es transaktional konsistent sein? | Use-Case-Grenze festlegen | Asynchrones Event prüfen |
| Muss ein Consumer später replayen? | Event-Versionierung und Idempotenz planen | Command/Request genügt vielleicht |
| Muss es unabhängig deploybar sein? | API/Event-Vertrag hart pflegen | Modularer Monolith kann reichen |