Wie teilt man komplexe Bedingungen auf und behält die Kurzschlussauswertung bei?

7

Manchmal können Bedingungen sehr komplex werden, deshalb teile ich sie für die Lesbarkeit gewöhnlich auf und gebe jeder Komponente einen aussagekräftigen Namen. Dies verhindert jedoch eine Kurzschlussauswertung, was ein Problem darstellen kann. Ich kam mit einem Wrapper-Ansatz, aber es ist meiner Meinung nach viel zu ausführlich.

Kann jemand dafür eine saubere Lösung finden?

Siehe Code unten für Beispiele, was ich meine:

%Vor%

Antwort auf Antworten:

Danke für all eure Ideen! Folgende Alternativen wurden bisher eingereicht:

  • Zeilen umbrechen und Kommentare hinzufügen
  • Verlasse wie
  • Methoden extrahieren
  • Frühe Rückkehr
  • Nested / Split up if's

Zeilen umbrechen und Kommentare hinzufügen:

Das Hinzufügen von Zeilenumbrüchen innerhalb einer Bedingung wird durch den Codeformatierer in Eclipse rückgängig gemacht (Strg + Umschalt + f). Inline-Kommentare helfen dabei, lassen aber in jeder Zeile wenig Platz und können zu unschönem Umbruch führen. In einfachen Fällen könnte dies jedoch ausreichen.

Gehen Sie wie folgt vor:

Die Beispielbedingung, die ich angegeben habe, ist ziemlich einfach, daher müssen Sie in diesem Fall möglicherweise keine Lesbarkeitsprobleme beheben. Ich habe an Situationen gedacht, in denen der Zustand viel komplexer ist, zum Beispiel:

%Vor%

Ich würde nicht empfehlen, das so zu lassen, wie es ist.

Methoden extrahieren:

Ich dachte über Extraktionsmethoden nach, wie es in mehreren Antworten vorgeschlagen wurde. Der Nachteil davon ist, dass diese Methoden typischerweise eine sehr geringe Granularität haben und möglicherweise selbst nicht sehr aussagekräftig sind, so dass sie Ihre Klasse durcheinander bringen können, zum Beispiel:

%Vor%

Dies würde es nicht wirklich verdienen, eine separate Methode auf Klassenebene zu sein. Außerdem müssen Sie alle relevanten Argumente an jede Methode übergeben. Wenn Sie eine separate Klasse nur für die Auswertung einer sehr komplexen Bedingung erstellen, ist dies möglicherweise eine gute Lösung IMO.

Was ich mit dem Booleschen Ausdruck versucht habe, ist, dass die Logik lokal bleibt. Beachten Sie, dass selbst die Deklaration von BooleanExpression lokal ist (ich glaube, ich habe noch nie einen Anwendungsfall für eine lokale Klassendeklaration gefunden!).

Frühzeitige Rückgabe:

Die Early-Return-Lösung scheint angemessen zu sein, obwohl ich das Idiom nicht favorisiere. Eine alternative Schreibweise:

%Vor%

Mir ist klar, dass die meisten Leute Etiketten und Pausen hassen, und dieser Stil ist vielleicht zu ungewöhnlich, um als lesbar angesehen zu werden.

Verschachtelt / aufgeteilt if's:

Es ermöglicht die Einführung aussagekräftiger Namen in Kombination mit optimierter Auswertung. Ein Nachteil ist der komplexe Baum der bedingten Anweisungen, die sich ergeben können

Showdown

Um zu sehen, welchen Ansatz ich favorisiere, habe ich mehrere der vorgeschlagenen Lösungen auf das oben dargestellte komplexe Ziel angewendet. Hier sind meine Ergebnisse:

geschachtelt / geteilt if's, mit aussagekräftigen Namen sehr ausführliche, aussagekräftige Namen helfen hier nicht wirklich bei der Lesbarkeit

%Vor%

verschachtelt / geteilt, falls mit Kommentaren weniger ausführlich, aber immer noch schwer zu lesen und einfach Fehler zu erstellen

%Vor%

frühe Rückgabe noch kompakter, aber der bedingte Baum bleibt genauso komplex.

%Vor%

extrahierte Methoden führt zu unsinnigen Methoden in Ihrer Klasse die Parameterübergabe ist ärgerlich

%Vor%

BooleanExpression Wrappers wurden erneut aufgerufen Beachten Sie, dass die Methodenparameter als final deklariert werden müssen Für diesen komplexen Fall ist die Ausführlichkeit IMO vertretbar Vielleicht werden Schließungen das leichter machen, wenn sie sich jemals darauf einigen (-

%Vor%

Ich schätze, es hängt wirklich von der Situation ab (wie immer). Für sehr komplexe Bedingungen kann der Wrapper-Ansatz verteidigbar sein, obwohl dies ungewöhnlich ist.

Danke für all Ihre Eingaben!

EDIT: nachträglicher Einfall. Es ist vielleicht noch besser, eine spezifische Klasse für komplexe Logik wie diese zu erstellen:

%Vor%

Die Logik ist komplex genug, um eine separate Klasse (und Unit-Test, yay!) zu rechtfertigen. Es wird den Code, der diese Logik verwendet, besser lesbar halten und die Wiederverwendung fördern, falls diese Logik woanders benötigt wird. Ich denke, das ist eine nette Klasse, denn es hat wirklich eine einzige Verantwortung und nur letzte Felder.

    
Adriaan Koster 18.12.2009, 15:01
quelle

11 Antworten

6

Ich finde Zeilenumbrüche und Leerzeichen machen eigentlich einen ziemlich guten Job:

%Vor%

Zugegebenermaßen funktioniert es besser mit meinem (unpopulären) Verstrebungsstil (oben nicht gezeigt), aber selbst mit dem Obenstehenden funktioniert es gut, wenn Sie die schließende und die öffnende Klammer auf ihre eigene Linie legen (damit sie nicht verloren gehen) Ende der letzten Bedingung).

Manchmal kommentiere ich sogar die einzelnen Bits:

%Vor%

Wenn Sie wirklich Dinge herausrufen möchten, tun mehrere if s es tun:

%Vor%

... und jeder optimierende Compiler kollabiert das. Für mich ist es aber wahrscheinlich etwas zu ausführlich.

    
T.J. Crowder 18.12.2009, 15:08
quelle
11

Sie können frühe Rückgabewerte (aus einer Methode) verwenden, um den gleichen Effekt zu erzielen:

[Einige Fixes angewendet]

%Vor%     
Itay Maman 18.12.2009 15:06
quelle
6

Wenn Ihr Ziel Lesbarkeit ist, warum nicht einfach die Zeilen durchbrechen und Kommentare hinzufügen?

%Vor%     
Eli Acherkan 18.12.2009 15:05
quelle
2

Der BoolescheAusdruckstyp scheint nicht nützlich genug zu sein, um außerhalb seiner Hauptklasse eine eigene Klasse zu sein, und er fügt Ihrer Anwendung auch ein gewisses intellektuelles Gewicht hinzu. Ich würde einfach nur private Methoden schreiben, die entsprechend benannt sind, um die gewünschten Überprüfungen auszuführen. Es ist viel einfacher.

    
Andy Gherna 18.12.2009 15:12
quelle
2

Sie müssen die Variablenzuweisung INSIDE der if's machen.

%Vor%

wird in

übersetzt %Vor%

Es ist oft vorteilhaft, dies trotzdem zu tun, da es die Konzepte benennt, nach denen Sie testen, wie Sie es in Ihrem Beispielcode deutlich machen. Dies erhöht die Lesbarkeit.

    
quelle
1

Ihre erste Lösung ist gut für diese Art von Komplexität. Wenn die Bedingungen komplexer wären, würde ich für jede Prüfung, die Sie ausführen müssen, private Methoden schreiben. Etwas wie:

%Vor%     
JuanZe 18.12.2009 15:50
quelle
1

Diese Frage stammt aus dem Jahr 2009, aber in der Zukunft (Java 8) werden wir in der Lage sein, Lambda-Ausdrücke zu verwenden, die für diesen Kontext genauso aussehen wie boolesche Ausdrücke, aber Sie können sie nur bei Bedarf verwenden.

%Vor%

Sie können das gleiche mit Java 5/6 machen, aber es ist weniger effizient und viel weniger kompliziert, mit anonymen Klassen zu schreiben.

    
aalku 04.02.2014 16:12
quelle
0

Einige gute Lösungen bereits, aber hier ist meine Variation. Normalerweise mache ich die Nullkontrolle als oberste Wächterklausel in allen (relevanten) Methoden. Wenn ich es in diesem Fall mache, hinterlässt es nur die Längen- und Gleichheitsüberprüfung in dem nachfolgenden if, was bereits als ausreichende Verringerung der Komplexität und / oder Verbesserung der Lesbarkeit angesehen werden könnte?

%Vor%     
Cornel Masson 18.12.2009 17:35
quelle
0

Teile es in eine separate Funktion (um die Lesbarkeit in main () zu verbessern) und füge einen Kommentar hinzu (damit die Leute verstehen, was du erreichen willst)

%Vor%

ETA: Ich mag auch Itays Idee, frühe Rückgabewerte in der ArgumentAreValid-Funktion zu verwenden, um die Lesbarkeit zu verbessern.

    
Eric Petroelje 18.12.2009 15:08
quelle
0

Ihre erste Lösung wird in vielen Fällen nicht funktionieren, einschließlich des Beispiels, das Sie oben angegeben haben. Wenn args null ist, dann

%Vor%

Ein Vorteil von Kurzschlüssen ist, dass sie die Laufzeit verringern. Ein weiterer Vorteil ist, dass Sie frühe Tests haben, die nach Bedingungen suchen, die dazu führen, dass spätere Tests Ausnahmen auslösen.

Wenn die Tests individuell einfach sind und alles komplex ist, weil es viele davon gibt, würde ich für die einfache Lösung "Zeilenumbrüche und Kommentare hinzufügen" stimmen. Dies ist einfacher zu lesen als das Erstellen einer Reihe zusätzlicher Funktionen.

Das einzige Mal, wenn ich Dinge in Subroutinen aufspalte, ist, wenn ein Einzeltest komplex ist. Wenn Sie eine Datenbank lesen oder eine große Berechnung durchführen müssen, dann rollen Sie diese in eine Subroutine, damit der Code auf oberster Ebene einfach zu lesen ist

%Vor%

Bearbeiten: Wie ich das komplexere Beispiel, das Sie gegeben haben, auflösen würde.

Wenn ich wirklich Bedingungen bekomme, die so komplex sind, versuche ich, sie in verschachtelte IFs aufzuteilen, um sie lesbarer zu machen. Wie ... und entschuldige mich, wenn das Folgende nicht wirklich deinem Beispiel entspricht, ich wollte die Klammern nicht zu genau studieren, nur für ein Beispiel wie dieses (und natürlich sind es die Klammern, die das Lesen erschweren) :

%Vor%

Das scheint mir so lesbar zu sein, wie es wahrscheinlich wird. In diesem Beispiel ist die "Top-Level" -Bedingung eindeutig die Beziehung von Position zu Min und Max, also hilft meiner Meinung nach das Aufbrechen, um Dinge zu klären.

Tatsächlich ist das obige wahrscheinlich effizienter, als alles in einer Zeile zu stempeln, weil die anderen erlauben, die Anzahl der Vergleiche zu reduzieren.

Persönlich kämpfe ich mit, wenn es eine gute Idee ist, einen komplexen Zustand in eine einzige Zeile zu bringen. Aber selbst wenn du es verstehst, besteht die Wahrscheinlichkeit, dass die nächste Person nicht kommt. Sogar einige ziemlich einfache Dinge, wie

gib s == null zurück? -1: s.length ();

Manchmal sage ich mir selbst, ja, ich verstehe, aber andere werden nicht, vielleicht besser schreiben

%Vor%     
Jay 18.12.2009 19:12
quelle
-1

Es ist wirklich nichts falsch mit dem ersten Stück Code; du überdenkst Dinge, IMO.

Hier ist ein anderer Weg, der zwar verständlich ist, aber leicht zu verstehen ist.

%Vor%     
Jonathan Feinberg 18.12.2009 15:08
quelle

Tags und Links