Warum eine Regel-Engine?

Bevor wir mit dem Programmieren beginnen, lassen Sie uns darüber sprechen, warum Sie überhaupt eine Regel-Engine benötigen:

  • Trennt die Geschäftslogik vom Kernanwendungscode
  • Ermöglicht es Nicht-Technikern, Regeln ohne vollständige Bereitstellung anzupassen
  • Macht Ihr System anpassungsfähiger an Veränderungen (und glauben Sie mir, Veränderungen kommen)
  • Verbessert die Wartbarkeit und Testbarkeit

Jetzt, da wir alle auf dem gleichen Stand sind, lassen Sie uns loslegen!

Die Kernkomponenten

Unsere Regel-Engine wird aus drei Hauptteilen bestehen:

  1. Regel: Die einzelne Geschäftsregel
  2. Regel-Engine: Das Gehirn, das die Regeln verarbeitet
  3. Fakt: Die Daten, auf denen unsere Regeln arbeiten werden

Lassen Sie uns diese nacheinander durchgehen.

1. Das Regel-Interface

Zuerst benötigen wir ein Interface für unsere Regeln:


public interface Rule {
    boolean evaluate(Fact fact);
    void execute(Fact fact);
}

Einfach, oder? Jede Regel weiß, wie sie sich selbst gegen einen Fakt auswertet und was zu tun ist, wenn sie zutrifft.

2. Die Fakt-Klasse

Als nächstes definieren wir unsere Fakt-Klasse:


public class Fact {
    private Map attributes = new HashMap<>();

    public void setAttribute(String name, Object value) {
        attributes.put(name, value);
    }

    public Object getAttribute(String name) {
        return attributes.get(name);
    }
}

Diese flexible Struktur ermöglicht es uns, beliebige Datentypen zu unseren Fakten hinzuzufügen. Denken Sie daran als einen Schlüssel-Wert-Speicher für Ihre Geschäftsdaten.

3. Die Regel-Engine-Klasse

Nun zum Hauptteil, unserer Regel-Engine:


public class RuleEngine {
    private List rules = new ArrayList<>();

    public void addRule(Rule rule) {
        rules.add(rule);
    }

    public void process(Fact fact) {
        for (Rule rule : rules) {
            if (rule.evaluate(fact)) {
                rule.execute(fact);
            }
        }
    }
}

Hier passiert die Magie. Die Engine durchläuft alle Regeln, wertet sie aus und führt sie bei Bedarf aus.

Alles zusammenfügen

Jetzt, da wir unsere Kernkomponenten haben, lassen Sie uns sehen, wie sie mit einem einfachen Beispiel zusammenarbeiten. Angenommen, wir bauen ein Rabattsystem für eine E-Commerce-Plattform.


public class DiscountRule implements Rule {
    @Override
    public boolean evaluate(Fact fact) {
        Integer totalPurchases = (Integer) fact.getAttribute("totalPurchases");
        return totalPurchases != null && totalPurchases > 1000;
    }

    @Override
    public void execute(Fact fact) {
        fact.setAttribute("discount", 10);
    }
}

// Verwendung
RuleEngine engine = new RuleEngine();
engine.addRule(new DiscountRule());

Fact customerFact = new Fact();
customerFact.setAttribute("totalPurchases", 1500);

engine.process(customerFact);

System.out.println("Rabatt: " + customerFact.getAttribute("discount") + "%");

In diesem Beispiel erhält ein Kunde, der über 1000 $ eingekauft hat, einen Rabatt von 10%. Einfach, effektiv und leicht anpassbar.

Weiterführende Schritte

Jetzt, da wir die Grundlagen beherrschen, lassen Sie uns einige Möglichkeiten zur Verbesserung unserer Regel-Engine erkunden:

1. Regel-Prioritäten

Fügen Sie ein Prioritätsfeld zu den Regeln hinzu und sortieren Sie sie in der Engine:


public interface Rule {
    int getPriority();
    // ... andere Methoden
}

public class RuleEngine {
    public void addRule(Rule rule) {
        rules.add(rule);
        rules.sort(Comparator.comparingInt(Rule::getPriority).reversed());
    }
    // ... andere Methoden
}

2. Regel-Verkettung

Erlauben Sie es Regeln, andere Regeln auszulösen:


public class RuleEngine {
    public void process(Fact fact) {
        boolean ruleExecuted;
        do {
            ruleExecuted = false;
            for (Rule rule : rules) {
                if (rule.evaluate(fact)) {
                    rule.execute(fact);
                    ruleExecuted = true;
                }
            }
        } while (ruleExecuted);
    }
}

3. Regel-Gruppen

Organisieren Sie Regeln in Gruppen für eine bessere Verwaltung:


public class RuleGroup implements Rule {
    private List rules = new ArrayList<>();

    public void addRule(Rule rule) {
        rules.add(rule);
    }

    @Override
    public boolean evaluate(Fact fact) {
        return rules.stream().anyMatch(rule -> rule.evaluate(fact));
    }

    @Override
    public void execute(Fact fact) {
        rules.forEach(rule -> {
            if (rule.evaluate(fact)) {
                rule.execute(fact);
            }
        });
    }
}

Leistungsüberlegungen

Obwohl unsere Regel-Engine ziemlich gut ist, gibt es immer Möglichkeiten zur Optimierung:

  • Verwenden Sie eine effizientere Datenstruktur zur Regel-Speicherung (z.B. einen Baum für hierarchische Regeln)
  • Implementieren Sie Caching für häufig abgerufene Fakten oder Regelbewertungen
  • Erwägen Sie parallele Verarbeitung für große Regelmengen

Wartungstipps

Um zu verhindern, dass Ihre Regel-Engine zu einem wilden Tier wird:

  • Dokumentieren Sie jede Regel gründlich
  • Implementieren Sie Versionskontrolle für Ihre Regeln
  • Erstellen Sie eine benutzerfreundliche Oberfläche für nicht-technische Benutzer zur Regeländerung
  • Überprüfen und bereinigen Sie regelmäßig veraltete Regeln

Das Fazit

Und da haben Sie es! Eine schlanke, effiziente Regel-Engine in etwa 150 Zeilen Code. Sie ist flexibel, erweiterbar und könnte Sie vor der nächsten Geschäftslogik-Apokalypse bewahren. Denken Sie daran, der Schlüssel zu einer guten Regel-Engine ist, sie einfach zu halten, während sie bei Bedarf Komplexität zulässt.

Bevor Sie gehen, hier ein Gedanke zum Nachdenken: Wie könnte dieses Regel-Engine-Konzept auf andere Bereiche Ihres Codebasises angewendet werden? Könnte es komplexe Entscheidungsprozesse in Ihrem aktuellen Projekt vereinfachen?

Viel Spaß beim Programmieren, und möge Ihre Geschäftslogik immer dynamisch großartig sein!

"Einfachheit ist die höchste Stufe der Vollendung." - Leonardo da Vinci (Er sprach nicht über das Programmieren, aber er hätte es durchaus tun können)

P.S. Wenn Sie tiefer in Regel-Engines eintauchen möchten, schauen Sie sich einige Open-Source-Projekte wie Easy Rules oder Drools an. Sie könnten Ihnen einige Ideen geben, um Ihre selbstgebaute Engine auf die nächste Stufe zu heben!