Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MBoegers committed Feb 20, 2023
1 parent 98024ef commit 42ac8a8
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
/out/
/.idea/
157 changes: 157 additions & 0 deletions BeispielKlasssenDiagramm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
# DataOrientedJava
Contains examples I create to demonstrate the application of data oriented programming in modern Java

In diesem Repository befindet sich ein kleines Beispiel in dem ich die Prinzipien des Data Oriented Programmings mit
Java 19+ und Preview Features demonstriere.
Dieses Beispiel verwende ich in Artikeln und Vorträgen zu dem Themenblock und werde es regelmäßig auf die neusten
Versionen von Java aktualisieren.

## Das Beispiel: RechnungenErstellen

In diesem Beispiel erstelle ich für verschiedene Arten von Kunden Rechnungen.
Kunden unterteilen sich in Privat- und Businesskunden, wobei
Businesskunden [Vorsteuerabzugsberechtigt](https://buchhaltungslexikon.de/lexikon/vorsteuerabzugsberechtigt/) sein
können.

Zusätzlich gibt es zwei Rechnungsarten: intern und extern.
Bei internen Rechnungen handelt es sich um Verrechnungen zu denen keine Rechnung im herkömmlichen Sinne versandt werden
muss.
Bei externen Rechnungen muss die Rechnung formatiert und als E-Mail an den Kunden versandt werden.

![Domain Modell als Klassendiagramm](BeispielKlasssenDiagramm.svg)

## Enthalten in dem aktuellen Stand

1. [JEP 409: Sealed Classes](https://openjdk.java.net/jeps/409) um die Auswahlmöglichkeiten bei der Rechnung und dem
Kunden zu modellieren
2. [JEP 395: Records](https://openjdk.org/jeps/395) um kompakte Data Carrier für Rechnungen und Kunden zu definieren
3. [JEP 394: Pattern Matching for instanceof](https://openjdk.org/jeps/394) um eine Fallunterscheidung zu machen wie ein
Kunde bzw. eine Rechnung verarbeitet wird
4. [JEP 433: Pattern Matching for switch (Fourth Preview)](https://openjdk.org/jeps/433) um die Fallunterscheidung
lesbarer zu machen
5. [JEP 432: Record Patterns (Second Preview)](https://openjdk.org/jeps/432) um direkt auf Record Inhalte zuzugreifen
6. [JEP 430: String Templates (Preview)](https://openjdk.org/jeps/430) um Texte noch besser angenehm zu formatiere
17 changes: 17 additions & 0 deletions src/io/github/mboegers/dop/invoice/Dummy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.github.mboegers.dop.invoice;

final class Dummy {
/**
* Simuliert einen Versand per Mail.
*/
static void sendViaMail(String empf, String txt) {
System.out.printf("Sende E-Mail an %s mit Inhalt:%n%s%n", empf, txt);
}

/**
* Simuliert ein Abspeichern in einer Datenbank
*/
static void storeInDB(String abt, double value) {
System.out.printf("Speicher %s€ zur Verrechnung mit Abteilung %s%n", value, abt);
}
}
13 changes: 13 additions & 0 deletions src/io/github/mboegers/dop/invoice/Kunde.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.mboegers.dop.invoice;

sealed interface Kunde permits Privatkunde, Businesskunde {
String name();

String mail();
}

record Privatkunde(String name, String mail) implements Kunde {
}

record Businesskunde(String name, String mail, boolean isVorsteuerAbzugsberechtigt) implements Kunde {
}
59 changes: 59 additions & 0 deletions src/io/github/mboegers/dop/invoice/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.github.mboegers.dop.invoice;

import java.util.List;

class Main {

/**
* Behandlet eine Rechnung abhing davon, ob sie intern oder extern ist.
* Verwendet JEP 432: Record Patterns (Second Preview) https://openjdk.org/jeps/432
*/
static void processRechnung(Rechnung rechnung) {
switch (rechnung) {
case InterneVerechnung(var abt, double wert) -> Dummy.storeInDB(abt, wert);
case ExternVersandt(Kunde kunde, var wert) -> {
double mwst = MwStRechner.SwitchExpressionWhenClause.calculateMwSt(kunde, wert);
var txt = formatMail(kunde.name(), wert, mwst);
Dummy.sendViaMail(kunde.mail(), txt);
}
}
}

/**
* Formatiert eine Mail Text
*/
static String formatMail(String name, double wert, double mwst) {
return """
Hallo %s,
Bitte senden Sie uns den Rechnungsbetrag in Höhe von %.2f€ plus %.2f€ MwSt.
Mit freundlichen Grüßen
Merlin Bögershausen
""".formatted(name, wert, mwst);
}

/**
* Formtiert eine Mail mit JEP 430: String Templates (Preview) https://openjdk.org/jeps/430
*/
/*
static String formatMail_Template(String name, double wert, double mwst) {
return FMT."""
Hallo \{name},
Bitte senden Sie uns den Rechnungsbetrag in Höhe von %.2f\{wert}€ plus %.2f\{mwst}€ MwSt.
Mit freundlichen Grüßen
Merlin Bögershausen
"""; // anstelle String.formatted(name, wert, mwst) mit Format
}
*/
public static void main(String[] args) {
var pk = new Privatkunde("Merlin", "");
var bk1 = new Businesskunde("adesso SE", "", false);
var bk2 = new Businesskunde("Eureg JUG", "", true);

System.out.println("Behandle Rechnung");
var rechnungen = List.of(new InterneVerechnung("HR", 10), new ExternVersandt(bk1, 10), new ExternVersandt(bk2, 10), new ExternVersandt(pk, 10));

rechnungen.forEach(Main::processRechnung);
}
}
93 changes: 93 additions & 0 deletions src/io/github/mboegers/dop/invoice/MwStRechner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.github.mboegers.dop.invoice;

/**
* Berechne MwSt für verschiedene Arten von Kunden
*/
final class MwStRechner {
private MwStRechner() {
}

/**
* Verwende Plain OOP Mittel
*/
final class PlainOOP {
private PlainOOP() {
}

/**
* ermöglicht einen einheitlichen Zugriff
*/
public static double calculateMwSt(Kunde kunde, double wert) {
return calculateMwSt(kunde, wert);
}

/**
* immer 10% des Kaufwertes für Privatkunden
*/
private static double calculateMwSt(Privatkunde p, double wert) {
return wert * 0.1d;
}

/**
* 0% wenn Vorsteuerabzugsberechtigt, sonst 10%
*/
private static double calculateMwSt(Businesskunde b, double wert) {
return b.isVorsteuerAbzugsberechtigt() ? 0d : wert * 0.1d;
}
}

/**
* Verwendung JEP 394: Pattern Matching for instanceof https://openjdk.org/jeps/394
*/
final class InstanceOfPattern {
private InstanceOfPattern() {
}

public static double calculateMwSt(Kunde kunde, double wert) {
if (kunde instanceof Businesskunde b) { // abhängig von dem Vorsteuerabzug
if (b.isVorsteuerAbzugsberechtigt()) return 0.0d;
else return wert * 0.1d;
} else if (kunde instanceof Privatkunde) { // immer 10% des Kaufwertes
return wert * 0.1d;
} else { // behandle fehlende Implementierung
throw new IllegalArgumentException("Typ %s nicht implementiert".formatted(kunde));
}
}
}

/**
* Verwendung von JEP 433: Pattern Matching for switch (Fourth Preview) https://openjdk.org/jeps/433
*/
final class SwichExpression {
private SwichExpression() {
}

public static double calculateMwSt(Kunde kunde, double wert) {
return switch (kunde) {
case Businesskunde b -> {
if (b.isVorsteuerAbzugsberechtigt()) yield 0.0d;
else yield wert * 0.1d;
} // alternativ b.vorsteuerAbzug() ? 0.0d : wert * 0.1d;
case Privatkunde p -> wert * 0.1d;
};
}
}

/**
* Verwendung von JEP 433: Pattern Matching for switch (Fourth Preview) https://openjdk.org/jeps/433 und when-Clause
*/
final class SwitchExpressionWhenClause {
private SwitchExpressionWhenClause() {
}

public static double calculateMwSt(Kunde kunde, double wert) {
return switch (kunde) {
case Businesskunde b when b.isVorsteuerAbzugsberechtigt() -> 0.0d;
case Businesskunde b -> wert * 0.1d;
case Privatkunde p -> wert * 0.1d;
};
}

}
}

11 changes: 11 additions & 0 deletions src/io/github/mboegers/dop/invoice/Rechnung.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.mboegers.dop.invoice;

sealed interface Rechnung permits InterneVerechnung, ExternVersandt {
}

record InterneVerechnung(String abteilung, double wert) implements Rechnung {
}

record ExternVersandt(Kunde kunde, double wert) implements Rechnung {
}

0 comments on commit 42ac8a8

Please sign in to comment.