Enum für Bedin­gung B01

enums b01 01

Ausgangslage

Für die Bedingung B01 werden standard­mäßig 2 Metho­den für die ers­ten bei­den Bedingungs­werte ge­ne­riert:

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * <b>B01/01: &lt; 20,00 - gering</b>
 */
boolean isBestellwert_Kleiner2000();

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * <b>B01/02: 20,00 - 75,00 - normal</b>
 */
boolean isBestellwert_20007500();

Jetzt soll für diese Bedingung nur noch eine Methode ge­ne­riert und die Werte als Enum übergeben werden.

Erweiterung der Konfiguration

Da diese Konfigurationserweiterungen gezielt nur für die Entscheidungstabelle gedacht sind, werden sie in einer neuen Konfigurationsdatei für die Ent­schei­dungs­tabelle definiert. Sie hat denselben Namen wie die Ent­schei­dungs­tabelle, aller­dings ergänzt um die Datei­endung ".yaml":

config et 01

Die Ent­schei­dungs­tabellen-Konfiguration resources/lfet/demo/Rechnungsbetrag.lfet.yaml erhält die folgenden Einträge:
lfet:                          # 1)

  ide:
    java:

      interface.enum:          # 2)
        1:
          symbol: Intervall
          include.tags.title: Bestellwert
          exclude.tags.title: Rabatt

Die Einträge im Detail

1)  lfet:

Der Basis-Eintrag in allen YAML-Konfi­gura­tionsdateien für LF‑ET.

1:

Die Enum-Definitionen werden nummeriert, hier beginnt die Enum-De­fi­ni­tion Nr. 1

symbol: Intervall

Das Enum soll das Symbol des Wertes enthalten, zusätzlich soll je­weils aus dem Symbol ein Intervall abgeleitet werden (Unter- und Ober­grenze), inkl. passender Zugriffs‑ und Aus­wertungs­methoden.

include.tags.title: Bestellwert

Eine Liste von Schlüssel­worten, von denen mindestens eines im Titel der Bedingung oder Ak­tion vorkommen muss, damit diese Enum-De­fi­ni­tion bei der Ge­ne­rie­rung verwendet wird.

Zu Bestellwert passen B01 und B04:

enums et 01

exclude.tags.title: Rabatt

Eine Liste von Schlüssel­worten, von denen keines im Titel der Bedingung oder Ak­tion vorkommen darf, damit diese Enum-De­fi­ni­tion bei der Ge­ne­rie­rung verwendet wird.

Mit Rabatt wird B04 ausgeschlossen.
 

Geschmackssache:

  • Da in diesem Beispiel die Parameterlisten (Interval, Bestellwert, Rabatt) jeweils nur ein Element enthalten, wurden die Werte hier nicht als Liste, sondern als einfaches Argument angegeben

  • Bei Listen in YAML hat man mit LF-ET die Wahl, ob man die Elemente der Liste

    • entweder als YAML-Aufzählung, d.h. jeweils mit vorangestelltem Minus-Zeichen in einer eigenen Zeile,

    • oder durch Komma getrennt, als Argument in einer Zeile angibt

Ergebnisse für B01

Nur noch eine Methode

  • Nicht mehr für jeden Bedingungs-Wert eine Methode

  • Sondern nur noch eine Methode für die Bedingung

  • Die Werte werden jeweils als Enum über­ge­ben

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * The enum generation has been triggered in project.ini by:<br>
 * - <b>ide.java.interface.enum.1</b>: symbol=Intervall; include.tags.title=Bestellwert; exclude.tags.title=Rabatt
 */
boolean isEnum(Rechnungsbetrag_iFace.Bestellwert arg0);

 

Ein Enum

  • Für jeden Bedingungswert ein Enum-Wert

  • Bei Bedingungen nicht für den letzten Wert (hier >75), da für diesen immer ein ELSE-Zweig gene­riert wird

  • Werden in der Anwendung alle Werte der Bedingung benötigt, so kann dies über den Schlüssel interface.enum​.options: allValues festgelegt werden

  • Zusätzlich werden in diesem Beispiel bei der Ge­ne­rie­rung fachliche In­for­ma­tio­nen aus der Ent­schei­dungs­tabelle über­nommen:

    • Das Symbol des Wertes als String

    • Unter- und Ober­gren­zen der Inter­valle, die Anzahl der gewünschten Nachkommastellen wird dabei automatisch ermittelt

    • Inklusive dazu­gehö­ri­ger GETTER- und Aus­wertungs­methoden

  • Fach­liche Daten wer­den so auto­ma­tisch maschinen­ver­arbeit­bar

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * The enum generation has been triggered in project.ini by:<br>
 * - <b>ide.java.interface.enum.1</b>: symbol=Intervall; include.tags.title=Bestellwert; exclude.tags.title=Rabatt
 */
enum Bestellwert
{
    /**
     * <b>B01: Bestellwert</b><br>
     * <br>
     * <b>B01/01: &lt; 20,00 - gering</b>
     */
    $001("< 20,00", Double.NEGATIVE_INFINITY, 19.99),

    /**
     * <b>B01: Bestellwert</b><br>
     * <br>
     * <b>B01/02: 20,00 - 75,00 - normal</b>
     */
    $002("20,00 - 75,00", 20.0, 75.0);

    private final String symbol;
    private final double symbolMin;
    private final double symbolMax;

    Bestellwert(String symbol, double symbolMin, double symbolMax)
    {
        this.symbol = symbol;
        this.symbolMin = symbolMin;
        this.symbolMax = symbolMax;
    }

    public String getSymbol()
    {
        return symbol;
    }

    public double getSymbolMin()
    {
        return symbolMin;
    }

    public double getSymbolMax()
    {
        return symbolMax;
    }

    public boolean isInSymbolInterval(double d)
    {
        return d >= symbolMin && d <= symbolMax;
    }

    public boolean isInSymbolInterval(int i)
    {
        return i >= symbolMin && i <= symbolMax;
    }
}

 

Anpassung der Implementierung

Dies ist die einzige manuelle Anpassung, alles andere wird automatisch generiert.

Vorher: 2 Methoden für B01

In der ursprünglichen Version mussten für die Bedingung B01 noch 2 Methoden implementiert werden:

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * <b>B01/01: &lt; 20,00 - gering</b>
 */
@Override
public boolean isBestellwert_Kleiner2000() {
    return model.getBestellwert().compareTo(bigDecimal(20.00)) < 0;
}

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * <b>B01/02: 20,00 - 75,00 - normal</b>
 */
@Override
public boolean isBestellwert_20007500() {
    return model.getBestellwert().compareTo(bigDecimal(20.00)) >= 0 &&
            model.getBestellwert().compareTo(bigDecimal(75.00)) <= 0;
}

vertical space 05px

Jetzt: Nur noch eine Methode

Durch die Enum-Generierung ist jetzt nur noch eine Methode notwendig:

/**
 * <b>B01: Bestellwert</b><br>
 * <br>
 * <b>B01/01: &lt; 20,00 - gering</b>
 */
@Override
public boolean isEnum(Rechnungsbetrag_iFace.Bestellwert arg0) {
    return model.getBestellwert().compareTo(bigDecimal(arg0.getSymbolMin())) >= 0 &&
           model.getBestellwert().compareTo(bigDecimal(arg0.getSymbolMax())) <= 0;
}

vertical space 05px

Automatisch angepasste Methoden-Aufrufe im Regel­modul

So sehen die neu generierten Methodenaufrufe im Regel­modul jetzt aus:

if (iface.isEnum(Rechnungsbetrag_iFace.Bestellwert.$001) /* < 20,00 - gering */)
{
    // Rule R01 ---->

    iface.doTrace("Rechnungsbetrag", "20260224.141242", 7, 1);

    iface.doPortoBerechnen();
    iface.doRechnungsbetrag_Akt();

    // Rule R01 <----
}
else if (iface.isEnum(Rechnungsbetrag_iFace.Bestellwert.$002) /* 20,00 - 75,00 - normal */)
{

Vorteile

  • Mit Enums kann die Implementierung und Pflege der Methoden für Bedingungen und Aktionen deutlich effizienter und sicherer erfolgen:

    • anstatt einer Implementierung pro Wert

    • jetzt nur noch eine Implementierung pro Bedingung oder Ak­tion

  • In vielen Fällen können fachliche Änderungen an den Werten in der Ent­schei­dungs­tabelle rein über die Enums und das Regel­modul abgebildet werden, so dass die Implementierungen der Methoden davon nicht betroffen sind

    • Änderung von Zahlen­werten oder anderen Inhalten

    • Neue oder gelöschte Werte

    • etc.

  • fachliche Daten können bei der Gene­rie­rung leistungs­stark und sicher in die Anwen­dung über­nommen werden, wie z.B. Zahlen, Zahlen­reihen, Inter­valle, Texte, etc.