mitmario.dev

Synthese: die Rabattstaffel

JavaScript Im Browser 3 Min Lesezeit 3 BeispieleLektion 8 von 9

Der letzte Halt dieses Abschnitts bringt zusammen, was einzeln schon dastand: Vergleiche, logische Verknüpfung und Verzweigung. Der Anlass ist eine Regel, wie sie in echten Anwendungen vorkommt, also eine mit mehreren Bedingungen gleichzeitig.

Erst aufschreiben, dann tippen

Vier Regeln in der richtigen Reihenfolge
// Versandkosten nach drei Regeln, plus einem Rest.
function versandInCent(warenkorbInCent, istAbholung) {
  if (istAbholung) {
    return 0;
  }
  if (warenkorbInCent >= 5000) {
    return 0;
  }
  if (warenkorbInCent >= 2000) {
    return 295;
  }
  return 495;
}

console.log("Abholung:        ", versandInCent(1000, true));
console.log("6000 Cent:       ", versandInCent(6000, false));
console.log("3000 Cent:       ", versandInCent(3000, false));
console.log("1000 Cent:       ", versandInCent(1000, false));

Der Ablauf ist immer derselbe, und er beginnt nicht im Editor.

Erstens: Schreib die Fälle auf. Auf Papier, in einem Kommentar, egal wo. Ein Satz je Fall, in der Sprache des Kunden und nicht in der des Computers.

Zweitens: Leg die Reihenfolge fest. Geh die Liste durch und frag bei jedem Paar: Kann ein Kunde auf beide passen? Wenn ja, muss der speziellere Fall nach oben.

Drittens: Tipp es hin. Ein if je Fall, jedes mit return, und der Rest ganz unten ohne Bedingung.

Wenn du es in dieser Reihenfolge machst, ist der Code nur noch Abschreiben. Wenn du direkt tippst, denkst du über Fälle und Syntax gleichzeitig nach, und dabei verliert man Fälle.

Beachte im Beispiel, dass jeder Zweig sofort mit return aussteigt. Das ist der frühe Ausstieg aus Lektion 3.5, und er macht die else-Zweige überflüssig: Wenn du in Zeile drei zurückgekehrt bist, kommt Zeile fünf ohnehin nicht mehr dran.

Überlappende Bedingungen

Wenn sich zwei Regeln überlappen
// Zwei Regeln treffen auf denselben Kunden zu: Mitglied UND über 100.
// In dieser Reihenfolge gewinnt die falsche.
function rabattFalsch(wert, istMitglied) {
  if (wert >= 100) {
    return 5;
  }
  if (istMitglied && wert >= 100) {
    return 10;
  }
  return 0;
}

// Die engere Regel gehört nach oben.
function rabattRichtig(wert, istMitglied) {
  if (istMitglied && wert >= 100) {
    return 10;
  }
  if (wert >= 100) {
    return 5;
  }
  return 0;
}

console.log("Mitglied, 120 Euro, falsch herum: ", rabattFalsch(120, true));
console.log("Mitglied, 120 Euro, richtig herum:", rabattRichtig(120, true));

Das ist die eigentliche Schwierigkeit, und sie sieht harmlos aus.

Ein Mitglied, das für 120 Euro bestellt, passt auf zwei Regeln: „ab 100 Euro” und „Mitglied ab 100 Euro”. Beide sind wahr. Welche gilt, entscheidet allein die Reihenfolge im Code, und in der falschen Fassung bekommt das Mitglied 5 statt 10 Prozent.

Auffallen wird das niemandem beim Lesen des Codes. Beide Fassungen sehen richtig aus, beide laufen fehlerfrei durch, und für Nicht-Mitglieder stimmt sogar das Ergebnis. Es beschwert sich irgendwann ein Kunde.

Die Prüfung dafür ist eine Frage: Gibt es einen Fall, der auf zwei Regeln passt? Wenn ja, gehört die engere nach oben. Enger heißt: Sie hat mehr Bedingungen oder eine höhere Schwelle.

Bei der Aufgabe gleich hast du drei Regeln, die sich alle drei überlappen können. Geh sie einmal von der speziellsten zur allgemeinsten durch, bevor du anfängst.

Warum hier kein switch passt

Warum hier kein switch passt
// Es gibt einen Trick, mit dem ein switch auch Bereiche kann.
function stufeMitSwitch(punkte) {
  switch (true) {
    case punkte >= 90:
      return "sehr gut";
    case punkte >= 70:
      return "befriedigend";
    default:
      return "durchgefallen";
  }
}

// Und die ehrliche Fassung daneben.
function stufeMitIf(punkte) {
  if (punkte >= 90) {
    return "sehr gut";
  }
  if (punkte >= 70) {
    return "befriedigend";
  }
  return "durchgefallen";
}

console.log("Mit switch(true):", stufeMitSwitch(95));
console.log("Mit if:          ", stufeMitIf(95));

Die Frage kommt nach der vorigen Lektion zu Recht: Das sind doch mehrere Fälle, ist das nicht genau ein switch?

Nein, und der Grund ist der aus Lektion 3.6. Ein switch vergleicht einen Wert gegen feste Möglichkeiten. Hier gibt es weder das eine noch das andere: Die Regeln prüfen drei verschiedene Dinge, und „ab 100 Euro” ist kein fester Wert, sondern ein Bereich.

Es gibt einen Trick, mit dem es trotzdem geht: switch (true) und dann in jedem case eine Bedingung. Das Beispiel zeigt ihn, und er funktioniert tatsächlich, weil jeder case gegen true verglichen wird.

Nimm ihn trotzdem nicht. Er ist eine Verkleidung: Es sieht aus wie ein switch, verhält sich aber wie eine if-Kette, und der Leser muss erst merken, dass in den case-Zeilen Bedingungen und keine Werte stehen. Ein Konstrukt, das man erklären muss, ist selten das richtige.

Was du gleich baust

Eine Rabattstaffel mit vier Regeln: ein Gutscheincode, der alles schlägt, ein Mitgliederrabatt ab einem Bestellwert, ein allgemeiner Rabatt ab demselben Bestellwert, und der Rest.

Die Prüfung ruft die Funktion mit fünf verschiedenen Kombinationen auf. Eine davon ist ein Mitglied mit Gutschein und hohem Bestellwert, also jemand, auf den drei der vier Regeln zutreffen. An dem entscheidet sich, ob deine Reihenfolge stimmt.

Zum Mitnehmen

Schreib die Fälle auf Papier auf, bevor du tippst. Überlappende Regeln sind die häufigste Fehlerquelle, und die Reihenfolge löst sie auf.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.