Versandregeln dasselbe Interface geben

JavaBeginner
Jetzt üben

Einführung

Ein kleiner Paketservice benötigt vergleichbare Angebote unterschiedlicher Versandregeln. Für ein Paket mit 500 Gramm sehen die vorbereiteten Tarifdaten 600 Cent bei Town und 200 Cent bei Steps vor. Du setzt diese normalen Angebote um und untersuchst anschließend die Gewichtsgrenze, an der sich ein Preis ändert.

Dieses Lab setzt Java-Klassen, Konstruktoren, Methoden, Listen und grundlegende Polymorphie voraus. Es führt ein Interface und ein ausdrückliches Angebotsergebnis ein. Parser und Startskript sind vorhanden; du implementierst die tatsächliche Zulässigkeitsprüfung und Preisberechnung. Die vom Autor geschätzte Dauer umfasst Lesen und gewöhnliche Korrekturen.

Einer Festpreisregel einen öffentlichen Vertrag geben

In diesem Schritt lässt du die Town-Regel einen echten Preis für zulässige Pakete liefern und übergewichtige Pakete ablehnen.

Ö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

cat zeigt eine Datei an, ohne sie zu ändern. Lies die kleine Tarifdatei und das Interface:

cat data/rates.tsv
cat src/ShippingRule.java

Die Tarifdatei verwendet TSV: durch Tabulatoren getrennte Felder ohne Kopfzeile. Eine flat-Zeile enthält type, Regel-ID, Höchstgewicht in Gramm und Centbetrag. Eine step-Zeile ergänzt die Stufengröße vor dem Centbetrag je Stufe. Town erlaubt hier höchstens 2,000 Gramm und kostet 600 Cent; Steps erlaubt 5,000 Gramm und kostet 200 Cent je angefangene 500 Gramm.

Ein interface beschreibt Methoden, die ein Aufrufer ohne Kenntnis der Implementierungsklasse verwenden kann. ShippingRule verspricht eine ID und ein Angebot für ein Paket. Eine Klasse deklariert implements ShippingRule und stellt beide öffentlichen Methoden bereit. Beim Aufruf von rule.quote(parcel) wird zur Laufzeit die zu diesem Objekt gehörende Implementierung gewählt. Typumwandlungen oder Verzweigungen nach Versandunternehmen sind unnötig.

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.

Parcel speichert ID, Anzeigenamen und Gramm bereits in privaten Feldern mit nur lesenden Methoden. Quote.priced(cents) erzeugt ein zulässiges Ergebnis, Quote.unavailable() ein unzulässiges. Der Konstruktor von FlatRule speichert seine Parameter. Ergänze die Methode quote, indem du vor der Preisrückgabe die Zulässigkeit prüfst. return beendet die Methode sofort; mit > bleibt ein Paket genau auf der Grenze zulässig.

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/FlatRule.java <<'JAVA'
public final class FlatRule implements ShippingRule {
    private final String id;
    private final int maxGrams;
    private final long cents;
    public FlatRule(String id, int maxGrams, long cents) {
        this.id = id; this.maxGrams = maxGrams; this.cents = cents;
    }
    public String id() { return id; }
    public Quote quote(Parcel parcel) {
        if (parcel.grams() > maxGrams) return Quote.unavailable();
        return Quote.priced(cents);
    }
}
JAVA

./quote.sh führt das bereitgestellte Startskript im aktuellen Verzeichnis aus. Es kompiliert src/*.java mit javac -encoding UTF-8 in ein temporäres Verzeichnis und startet Java mit UTF-8-Textkodierung. Jeder Lauf kompiliert die gespeicherten Quellen neu und verwendet keine alten Klassendateien. Ein Compilerfehler nennt Quelldatei und Zeile: korrigiere und speichere die Datei und wiederhole den Befehl. Ein falscher Pfad verursacht einen Dateifehler; wiederhole das angegebene cd und prüfe den Dateinamen, statt die Umgebung zurückzusetzen.

./quote.sh quote 500

Der Befehl quote erhält ein Gewicht in Gramm und zeigt jede Regel-ID mit Centbetrag oder UNAVAILABLE. Town sollte nun 600 anzeigen. Steps zeigt weiterhin 0, weil seine Startmethode absichtlich unvollständig ist; das ist kein echtes kostenloses Angebot.

Teste das Höchstgewicht und ein Gramm mehr:

./quote.sh quote 2000
./quote.sh quote 2001

Town wechselt von 600 zu UNAVAILABLE. Die inklusive Grenze bleibt erhalten, ohne data/rates.tsv zu ändern. Prüfe diesen Schritt, bevor du fortfährst.

Jede angefangene Gewichtsstufe berechnen

In diesem Schritt implementierst du die zweite Regel über dasselbe Interface mit Ganzzahlarithmetik statt Fließkomma-Geldbeträgen.

Arbeite im WebIDE-Terminal in /home/labex/project/parcels weiter. Jede angefangene 500-Gramm-Stufe kostet 200 Cent: 1–500 Gramm benötigen eine Stufe, 501–1,000 zwei und 1,001–1,500 drei. Daher kosten 500 Gramm 200 Cent, 501 Gramm aber 400 Cent. Normale Ganzzahldivision schneidet ab: 501 / 500 ergibt 1 und würde zu wenig berechnen.

Für positive Grammwerte rundet (grams + stepGrams - 1L) / stepGrams die Stufenanzahl auf. L lässt die Berechnung mit long erfolgen; auch die Multiplikation der Anzahl mit stepCents verwendet long. Zuerst wird das Höchstgewicht geprüft, damit ein nicht bedientes Paket keinen irreführenden Preis erhält.

Ersetze die gesamte Stufenregel-Datei durch diese Implementierung. Verwende dieselbe Here-Document-Technik wie zuvor:

cat > src/StepRule.java <<'JAVA'
public final class StepRule implements ShippingRule {
    private final String id;
    private final int maxGrams, stepGrams;
    private final long stepCents;
    public StepRule(String id, int maxGrams, int stepGrams, long stepCents) {
        this.id = id; this.maxGrams = maxGrams;
        this.stepGrams = stepGrams; this.stepCents = stepCents;
    }
    public String id() { return id; }
    public Quote quote(Parcel parcel) {
        if (parcel.grams() > maxGrams) return Quote.unavailable();
        long steps = (parcel.grams() + stepGrams - 1L) / stepGrams;
        return Quote.priced(steps * stepCents);
    }
}
JAVA
./quote.sh quote 500

Erwartete Ausgabe mit durch Tabulatoren getrennten Spalten:

Town 600
Steps 200

Überschreite nun eine Stufengrenze und die Zulässigkeitsgrenze:

./quote.sh quote 501
./quote.sh quote 5001

Bei 501 Gramm zeigt Steps 400. Bei 5,001 Gramm zeigen beide Regeln UNAVAILABLE: Das Gewicht ist gültig, aber kein Angebot verfügbar; das Paket ist nicht ungültig. Probiere absichtlich null Gramm:

./quote.sh quote 0

Dieser Befehl schlägt erwartungsgemäß mit INVALID_WEIGHT SAMPLE und Exitstatus 2 fehl. Er ändert weder Quellen noch Tarife. Gib zur Wiederherstellung einfach ein gültiges Gewicht an:

./quote.sh quote 1500

Beide Regeln zeigen jetzt 600. Diesen echten Gleichstand behandelst du im nächsten Lab. Zulässigkeits- und Preisentscheidungen liegen in austauschbaren Regelobjekten, während der Aufrufer weiterhin nur das Interface verwendet.

Zusammenfassung

Du hast zwei Regeln hinter einem Java-Interface implementiert, Zulässigkeit von ganzzahligen Centbeträgen getrennt und genaue Grenzen sowie das Aufrunden angefangener Stufen geprüft. Derselbe Aufrufer erhält nun sinnvolle Angebote, ohne deren Implementierung zu kennen.