[JAVA] Ein wenig Aufwand, um komplizierte Wenn-sonst zu beseitigen

Hintergrund

Wenn wir Codeüberprüfungen für Codierungsanfänger durchführen, sehen wir oft eine tiefe Verschachtelung von if-else. Selbst metrische Tools wie SonarQube ärgern sich über "zyklomatische Komplexität ist zu hoch".

Wenn Sie versuchen, die bedingte Verzweigung gründlich zu reduzieren, werden Sie häufig über Entwurfsmuster wie Strategiemuster und Statusmuster sprechen, aber selbst wenn Sie nicht so weit gehen, ist es eine Geschichte, dass der Code mit ein wenig Sorgfalt leichter zu erkennen ist. .. Für Anfänger.

Beispiel

Unten finden Sie den Code, um festzustellen, ob der Artikel zum Kauf angeboten wird.

public boolean canPurchase() {
    boolean result;

    //Sind Sie angemeldet?
    if (isLoggedIn()) {
        //Ist es auf Lager?
        if (existsStock()) {
            //Bei Nachnahme
            if (isPaymentMethodCash()) {
                result = true;
            //Für Kreditzahlung
            } else {
                //Ist Ihre Kreditkarte registriert?
                if (isCreditCardRegistered()) {
                    result = true;
                } else {
                    result = false;
                }
            }
        } else {
            result = false;
        }
    } else {
        result = false;
    }

    return result;
}

Dies ist ein typisches Beispiel für eine tiefe Verschachtelung, und der Code ist sehr schwer zu befolgen. Wenn ich den Code einer unbekannten Person betrachte, habe ich das Gefühl, dass ich mir des normalen Arbeitsablaufs wie unten gezeigt bewusst bin.

if (1_Normales System) {
    if (2_Normales System) {
        ...
        ...
        ... //Lange Bearbeitung
        ...
        ...
    } else {
        // 2_Anormales System
        return null;
    }
} else {
    // 1_Anormales System
    throw new SomeException();
}

In "besonderen" Fällen, z. B. wenn sie nicht angemeldet oder nicht vorrätig sind, sind andere Bedingungen (Zahlungsmethode und Kartenregistrierung) irrelevant und der Rückgabewert wird bedingungslos bestimmt (oder eine Ausnahme). Wird passieren). Trennen wir diese Fälle von anderer Logik.

Zuerst werde ich die Anmeldebedingungen trennen.

public boolean canPurchase() {

    //Bedingungslos falsch, wenn nicht angemeldet
    if (!isLoggedIn()) {
        return false;
    }

    //Ist es auf Lager?
    if (existsStock()) {
        //Bei Nachnahme
        if (isPaymentMethodCash()) {
            return true;
        //Für Kreditzahlung
        } else {
            //Ist Ihre Kreditkarte registriert?
            if (isCreditCardRegistered()) {
                return true;
            } else {
                return false;
            }
        }
    } else {
        return false;
    }
}

Im ersten Code wurde die lokale Variable "result" mit einem booleschen Wert und schließlich "return result" aufgefüllt, aber diesmal ist der boolesche Wert sofort "return". Es scheint, dass die Methode der Rückgabe, wenn der Rückgabewert festgelegt ist, ohne temporäre Variablen auf diese Weise zu verwenden, als frühe Rückgabe bezeichnet wird. Ebenso wie der obige Code wird die Methode, einen Sonderfall zu Beginn vorzeitig zurückzugeben und diesen Sonderfall danach auszuschließen, als Schutzklausel bezeichnet. Auf diese Weise müssen Sie die else-Klausel nicht verwenden und die Verschachtelung ist weg.

Lassen Sie uns auch die Lagerbedingungen trennen.

public boolean canPurchase() {

    //Bedingungslos falsch, wenn nicht angemeldet
    if (!isLoggedIn()) {
        return false;
    }

    //Bedingungslos falsch, wenn nicht vorrätig
    if (!existsStock()) {
        return false;
    }

    //Bei Nachnahme
    if (isPaymentMethodCash()) {
        return true;
    //Für Kreditzahlung
    } else {
        //Ist Ihre Kreditkarte registriert?
        if (isCreditCardRegistered()) {
            return true;
        } else {
            return false;
        }
    }
}

Ich denke, dass die Verschachtelung beseitigt wurde und es einfacher ist, den Prozess zu verfolgen. Es ist eine gute Möglichkeit, die Sichtbarkeit des Codes mit ein wenig Aufwand zu verbessern. Probieren Sie es also aus.

** * Schutzumfangsklausel ** Wenn Sie hier weiter gehen, ist dies bei Nachnahme immer "wahr", sodass Sie die Verschachtelung weiter reduzieren können, indem Sie auch hier eine Schutzklausel anwenden.

public boolean canPurchase() {

    //Bedingungslos falsch, wenn nicht angemeldet
    if (!isLoggedIn()) {
        return false;
    }

    //Bedingungslos falsch, wenn nicht vorrätig
    if (!existsStock()) {
        return false;
    }

    //Unbedingt für Nachnahme
    if (isPaymentMethodCash()) {
        return true;
    }

    //Ist Ihre Kreditkarte registriert?
    if (isCreditCardRegistered()) {
        return true;
    } else {
        return false;
    }
}

Dies mag jedoch eine Frage des Geschmacks oder der Politik sein, aber ich persönlich denke, dass es besser ist, dies nicht zu tun. Der Grund dafür ist, dass die Schutzklausel nur ein Sonderfall im Voraus ist und Nachnahme oder Kreditkartenzahlung im Normalfall übliche Bedingungen sind. Wenn die Bedingungen gleich sind, sollten Sie sie meiner Meinung nach parallel zu if-else anordnen. Wenn die Reihenfolge der Schutzklauseln wie unten gezeigt geändert wird, treten Probleme auf.

/**Schlechtes Beispiel. True wird bei Nachnahme zurückgegeben, auch wenn Sie nicht angemeldet sind**/
public boolean canPurchase() {

    //Unbedingt für Nachnahme
    if (isPaymentMethodCash()) {
        return true;
    }

    //Bedingungslos falsch, wenn nicht angemeldet
    if (!isLoggedIn()) {
        return false;
    }

    //Bedingungslos falsch, wenn nicht vorrätig
    if (!existsStock()) {
        return false;
    }

    //Ist Ihre Kreditkarte registriert?
    if (isCreditCardRegistered()) {
        return true;
    } else {
        return false;
    }
}

Ich denke, dass die Schutzklausel innerhalb des Bereichs gehalten werden sollte, der unabhängig beurteilt werden kann (unabhängig von der Reihenfolge).

Recommended Posts

Ein wenig Aufwand, um komplizierte Wenn-sonst zu beseitigen
[Einführung in JSP + Servlet] Eine kleine Animation ♬
Ich möchte ein kleines Symbol in Rails verwenden