From 42ac8a8a6b1f02ca0ec99f9e87398a96ace61e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Mon, 20 Feb 2023 12:42:01 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 2 + BeispielKlasssenDiagramm.svg | 157 ++++++++++++++++++ README.md | 32 +++- src/io/github/mboegers/dop/invoice/Dummy.java | 17 ++ src/io/github/mboegers/dop/invoice/Kunde.java | 13 ++ src/io/github/mboegers/dop/invoice/Main.java | 59 +++++++ .../mboegers/dop/invoice/MwStRechner.java | 93 +++++++++++ .../github/mboegers/dop/invoice/Rechnung.java | 11 ++ 8 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 BeispielKlasssenDiagramm.svg create mode 100644 src/io/github/mboegers/dop/invoice/Dummy.java create mode 100644 src/io/github/mboegers/dop/invoice/Kunde.java create mode 100644 src/io/github/mboegers/dop/invoice/Main.java create mode 100644 src/io/github/mboegers/dop/invoice/MwStRechner.java create mode 100644 src/io/github/mboegers/dop/invoice/Rechnung.java diff --git a/.gitignore b/.gitignore index 0e13eeb..935559c 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/BeispielKlasssenDiagramm.svg b/BeispielKlasssenDiagramm.svg new file mode 100644 index 0000000..40344f6 --- /dev/null +++ b/BeispielKlasssenDiagramm.svg @@ -0,0 +1,157 @@ + + + + + + + + + Kunde + + + + + + + + + Privatkunde + + + + + + + + + Businesskunde + + + + boolean isVorsteuerAbzugsberechtigt() + + + + + + + Rechnung + + + + + + + + + InterneVerechnung + + + + + + + + + ExternVersandt + + + + + + + + MwSt 18% ist anzuwenden + + + + + + Vorsteuerabzugsberechtigung heißt 0% MwSt + + + + + + In der Buchfürhung hinterlegt + + + + + + An externen Empfänger versandt + + + + + + + + + + + + + + + + + + + + + + n + + 1 + + + + diff --git a/README.md b/README.md index 230da11..25e7c5a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/io/github/mboegers/dop/invoice/Dummy.java b/src/io/github/mboegers/dop/invoice/Dummy.java new file mode 100644 index 0000000..da12570 --- /dev/null +++ b/src/io/github/mboegers/dop/invoice/Dummy.java @@ -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); + } +} diff --git a/src/io/github/mboegers/dop/invoice/Kunde.java b/src/io/github/mboegers/dop/invoice/Kunde.java new file mode 100644 index 0000000..b6adc74 --- /dev/null +++ b/src/io/github/mboegers/dop/invoice/Kunde.java @@ -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 { +} diff --git a/src/io/github/mboegers/dop/invoice/Main.java b/src/io/github/mboegers/dop/invoice/Main.java new file mode 100644 index 0000000..0c2af0a --- /dev/null +++ b/src/io/github/mboegers/dop/invoice/Main.java @@ -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); + } +} diff --git a/src/io/github/mboegers/dop/invoice/MwStRechner.java b/src/io/github/mboegers/dop/invoice/MwStRechner.java new file mode 100644 index 0000000..d9be839 --- /dev/null +++ b/src/io/github/mboegers/dop/invoice/MwStRechner.java @@ -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; + }; + } + + } +} + diff --git a/src/io/github/mboegers/dop/invoice/Rechnung.java b/src/io/github/mboegers/dop/invoice/Rechnung.java new file mode 100644 index 0000000..c655bc4 --- /dev/null +++ b/src/io/github/mboegers/dop/invoice/Rechnung.java @@ -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 { +} +