Austauschbare Versandregeln vergleichen

JavaBeginner
Jetzt üben

Einführung

Der Paketservice kann Preise ermitteln, doch seine Vergleichsmethode liefert noch keine Gewinner. Du lässt sie Regelobjekte vergleichen, alle Gleichstände beim Mindestpreis bewahren und eine vollständige Angebotsdatei für mehrere Pakete speichern.

Dieses Lab startet unabhängig mit den beiden fertigen Regelimplementierungen aus dem vorherigen geführten Lab. Dessen Interface, Zulässigkeit und ganzzahlige Stufenpreise werden vorausgesetzt. Du ergänzt eine neue parametrierte Instanz einer vorhandenen Regel, statt einen weiteren Preisalgorithmus zu erfinden. Alle Tarife sind synthetisch. Die Dauer ist eine Schätzung des Autors.

Über das Interface vergleichen

In diesem Schritt implementierst du eine Vergleichsmethode für jede bereitgestellte ShippingRule, einschließlich einer dem Vergleich noch unbekannten Implementierung.

Öffne den Tab WebIDE und wähle im Menü Terminal → New Terminal, um das integrierte Terminal zu öffnen. Führe die folgenden Befehle dort aus. Alle Befehle laufen in derselben Shell; cd ändert deren Arbeitsverzeichnis. Wenn du ein Terminal neu öffnest, wiederhole den Befehl cd. JDK und Quellcodegerüst sind vorbereitet; du musst kein Build-Werkzeug installieren.

cd /home/labex/project/parcels
./quote.sh quote 1500

Town und Steps zeigen beide 600. Dieser normale Gleichstand zeigt, weshalb nur eine günstigste Regel eine gültige Wahl verlieren würde. Der vollständige öffentliche Vertrag und Eingabebereich lauten:

Zum öffentlichen Vertrag gehören ShippingRule.id() und ShippingRule.quote(Parcel) sowie Quote.eligible() und Quote.cents(). RuleFactory.flat(String, int, long) und RuleFactory.stepped(String, int, int, long) erzeugen Regelobjekte; QuoteEngine.bestRules(Parcel, List<ShippingRule>) liefert die IDs aller günstigsten Regeln. Mit diesen Signaturen kann derselbe Aufrufer verschiedene Implementierungen verwenden. Du darfst die Implementierungsklassen anders organisieren und dazu auch RuleFactory ändern. Erhalte diese öffentlichen Methoden sowie das vorgegebene Befehls- und Ausgabeformat; interne Klassennamen der Factory und dein Editor werden nicht bewertet.

Zulässige Paketgewichte sind ganze Zahlen von 1 bis 1,000,000 Gramm. Gewichtsgrenzen und Stufengrößen sind ebenfalls ganze Zahlen von 1 bis 1,000,000; jeder Festpreis oder Stufenpreis ist eine ganze Zahl von 0 bis 1,000,000 Cent. Ein zulässiges Angebot zu null Cent ist gültig. Es unterscheidet sich von Quote.unavailable(): Dort ist eligible() false, und der gespeicherte Centbetrag darf nicht am Vergleich teilnehmen. Berechnete Beträge werden in einem long gespeichert, damit ein großes gültiges Produkt keinen 32-Bit-int überlaufen lässt. Alle Tarife, Personen und Paketnamen sind synthetisch; dies sind keine aktuellen Preise echter Versandunternehmen.

Der Vergleich erhält eine List<ShippingRule>. Jedes Element kann anders implementiert sein; eine erweiterte for-Schleife besucht alle Objekte. Rufe quote(parcel) auf, statt Regelnamen zu prüfen oder mit instanceof ihre Geschäftslogik nachzubauen.

Beginne mit einer leeren Gewinnerliste und Long.MAX_VALUE, dem größten long, als Vergleichs-Sentinel. Überspringe unzulässige Angebote mit continue. Ein strikt kleinerer Preis ersetzt das bisherige Minimum; clear() entfernt deshalb alte Gewinner. Ein gleicher Preis ergänzt seine ID. Es sind zwei getrennte if-Anweisungen: Auch ein gerade neu festgelegtes Minimum muss aufgenommen werden. Ist nichts zulässig, bleibt die Liste leer.

Der folgende Befehl ersetzt eine Java-Quelldatei. cat schreibt den Text zwischen den beiden JAVA-Zeilen in den Pfad hinter >; die Anführungszeichen des Anfangsmarkers verhindern Shell-Ersetzungen im Java-Code. Füge den gesamten Block ein, einschließlich des abschließenden JAVA allein in einer Zeile. Du kannst dieselbe Datei auch in WebIDE bearbeiten, speichern und zum WebIDE-Terminal zurückkehren. Erscheint nach unvollständigem Einfügen eine Fortsetzungsaufforderung, drücke Ctrl+C und füge den vollständigen Block erneut ein.

cat > src/QuoteEngine.java <<'JAVA'
import java.util.ArrayList;
import java.util.List;
public final class QuoteEngine {
    public static List<String> bestRules(Parcel parcel, List<ShippingRule> rules) {
        List<String> winners = new ArrayList<>();
        long lowest = Long.MAX_VALUE;
        for (ShippingRule rule : rules) {
            Quote quote = rule.quote(parcel);
            if (!quote.eligible()) continue;
            if (quote.cents() < lowest) {
                lowest = quote.cents();
                winners.clear();
            }
            if (quote.cents() == lowest) winners.add(rule.id());
        }
        return winners;
    }
}
JAVA
./quote.sh batch data/parcels.tsv data/rates.tsv

batch erhält einen Paket-TSV-Pfad und einen Tarif-TSV-Pfad. Paketzeilen enthalten ID, Anzeigenamen und ganzzahlige Gramm. Die Ausgabe gruppiert jedes Paket mit allen Angeboten und einer BEST-Zeile. UNAVAILABLE bedeutet, dass eine Regel das Paket nicht transportieren kann; BEST NONE, dass keine es kann. Ein gültiger Stapel ohne zulässiges Angebot endet erfolgreich mit Status 0.

Bei P02 müssen Town und Steps in BEST stehen; P03 ist ein Gramm schwerer und nur Town gewinnt. P01 und P02 heißen beide Gift, doch verschiedene IDs trennen ihre Angebote. Für P04 ist keine Regel zulässig. Erhalte jedes Paket und jede Regel, auch nicht verfügbare Ergebnisse.

Eine weitere Regel registrieren und vollständige Angebote speichern

In diesem Schritt registrierst du ohne Änderung am Vergleich eine weitere Festpreisinstanz und speicherst später lesbare Ergebnisse für den Paketservice.

Arbeite im WebIDE-Terminal in /home/labex/project/parcels weiter. Der Tarifleser baut die gewünschten Implementierungen über RuleFactory. Eine weitere flat-Zeile erzeugt deshalb ein neues Objekt mit eigenen Parametern. Lass die ursprünglichen data/-Dateien unverändert. cp erstellt eine Arbeitskopie; printf schreibt Text, \t steht für einen Tabulator und \n beendet die Zeile. >> hängt an eine Datei an, statt sie zu ersetzen.

cp data/rates.tsv work/rates.tsv
printf 'flat\tRelay\t6000\t600\n' >> work/rates.tsv
./quote.sh batch data/parcels.tsv work/rates.tsv

Relay ist bis einschließlich 6,000 Gramm für 600 Cent zulässig. P02 hat nun drei gleich günstige Gewinner, P04 mit 6,500 Gramm weiterhin keinen. Du hast die registrierte Regelsammlung geändert; der ursprüngliche Vergleich funktioniert weiter.

Die Ausgabe ist das tatsächliche Angebotsergebnis. > speichert die Standardausgabe in einer Datei und ersetzt eine vorhandene gleichnamige Datei. Speichere nur einen gültigen Stapel, denn die Shell öffnet die Ausgabedatei, bevor Java die Eingaben prüft:

./quote.sh batch data/parcels.tsv work/rates.tsv > work/quotes.tsv
cat work/quotes.tsv

Jede ID braucht eine PARCEL-Zeile, eine QUOTE-Zeile pro registrierter Regel und eine BEST-Zeile mit allen zulässigen Mindestpreis-IDs, durch Kommas getrennt, oder NONE. Beträge bleiben ganzzahlige Cent. Regeln und Gewinner dürfen der Registrierungsreihenfolge folgen; entscheidend sind Mitglieder und Beziehungen.

Ein ungültiges Gewicht unterscheidet sich von einem gültigen Paket ohne Angebot. Der vorbereitete ungültige Beispieldatensatz enthält BAD mit null Gramm. Der Parser prüft den ganzen Stapel vor jeder Angebotsausgabe. Ein ungültiger Stapel endet mit Status 2, schreibt eine erklärende Meldung auf die Standardfehlerausgabe und erzeugt keine Angebotszeilen. Führe diesen absichtlichen Fehler ohne Umleitung auf deine gute Datei aus:

./quote.sh batch data/invalid-parcels.tsv work/rates.tsv

Erwarte INVALID_WEIGHT BAD. Kehre zur gültigen Paketdatei zurück:

./quote.sh batch data/parcels.tsv work/rates.tsv

Ursprüngliche Paket- und Tarifdaten sowie deine gute work/quotes.tsv bleiben erhalten. Korrigiere und speichere bei Compilerfehlern die genannte Datei; wiederhole bei Pfadfehlern cd /home/labex/project/parcels und starte erneut. Das Startskript baut bei jedem Lauf gespeicherte Quellen neu und verwendet wie zuvor ausdrücklich UTF-8.

Die Prüfungen kompilieren unveränderte Kopien in temporären Testdaten, auch mit anderen gültigen Parametern und Interface-Implementierungen. Sie ergänzen keine fehlenden Ergebnisse im laufenden Arbeitsbereich und überschreiben ihn nicht. Dies ist eine Funktionsbewertung in einer Lernumgebung, kein Schutz vor durch Administratoren gefälschten Dateien.

Zusammenfassung

Du hast Interface-Objekte ohne versandunternehmensspezifische Zweige verglichen, alle gleichen Mindestpreise bewahrt und eine gültige Angebotslosigkeit ausdrücklich dargestellt. Eine zusätzliche konfigurierte Regel nutzt denselben Ablauf. Die gespeicherte Datei erhält Identität und vollständige Auswahl jedes Pakets.