Wie kann ich meinen Zustand neu formatieren, um ihn zu verbessern?

35

Ich habe eine Bedingung

if(exists && !isDirectory || !exists)
{}

Wie kann ich es ändern, damit es verständlicher wird?

Spynet
quelle
1
Welchen Wert hat isDirectory, wenn es existiert, ist false?
Marktani
1
Es gibt Bool-Typ, IsDirectory ist auch BOOL-Typ Variablen
Spynet
5
if (! isDirectory) ... (existiert ||! existiert) ist immer wahr.
Hai
@Shark - Was ist, wenn existsund isDirectorybeide wahr sind?
Pasawaya
Ich las den Titel als "Ich habe ein Persönlichkeitsproblem, kann ich meine Gedanken löschen, um es zu beheben". Ja, ich bin müde.
Annan

Antworten:

110

|| ist kommutativ so

if(!exists || (exists && !isDirectory))

ist gleichwertig.

Nun, weil existiert, ist es immer wahr, im zweiten Teil von ||können Sie Folgendes fallen lassen &&:

if(!exists || !isDirectory)

Oder Sie können noch einen Schritt weiter gehen und Folgendes tun:

if(!(exists && isDirectory))
Ratschenfreak
quelle
5
Was hier impliziert, aber nicht explizit erwähnt wurde, ist, dass &&(zumindest in den meisten bekannten Sprachen - es kann Ausnahmen geben) höhere Priorität hat als ||. Also a && b || cist gleichbedeutend mit (a && b) || caber nicht mit a && (b || c).
Péter Török
27
Ich denke, dass !exists || !isDirectoryist mehr „verständlich“, weil, isDirectorykann nicht wahr sein , wenn !exists. Als Mensch werden wir also sagen, "wenn es nicht existiert oder [existiert und es] kein Verzeichnis ist".
Duros
6
Ich bevorzuge! Existiert || ! isVerzeichnis über das letzte.
Apoorv Khurasia
3
||ist nur kommutativ, wenn sie für Werte ohne Nebenwirkungen verwendet wird. Wenn sie beispielsweise für Funktionen verwendet werden, werden einige Funktionen möglicherweise nicht aufgerufen (Kurzschluss) oder geben einen anderen Wert in einer anderen Reihenfolge zurück.
Orlp
26
Jeder, der sich auf die relative Priorität von '&&', '||', '==', '! =' Usw. verlässt und seine Absicht nicht mit Klammern deutlich macht, verdient es, erschossen zu werden. In allen Sprachen so etwas wie 'a & b || c 'ist gleichbedeutend mit einem Kommentar, der besagt, dass der Autor die ganze Sache in seiner Eile vermasselt hat, um zu vermeiden, dass ein paar zusätzliche Zeichen eingegeben werden.
Brendan
51

Als Prozess schlage ich vor, eine Wahrheitstabelle zu erstellen:

e = exists
d = isDirectory

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0

Dies entspricht der NANDOperation , die einfach ist:

!(exists && isDirectory)

Wenn Sie sich nicht an alle Ihre Logikgatter erinnern, hat Wikipedia eine nette Referenz mit den Wahrheitstabellen .


@Christoffer Hammarström brachte einen wichtigen Punkt über den Zustand der Bindung isDirectoryan den Staatexists . Angenommen, sie verweisen auf dieselbe Referenz und es ist nicht möglich, einen Zustand zu haben, in dem die Referenz nicht existiert und ein Verzeichnis ist, kann die Wahrheitstabelle wie folgt geschrieben werden:

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | n/a
1 | 0 | 1
1 | 1 | 0

Das n/a wird verwendet, um einen Zustand darzustellen, der keine Rolle spielt. Akzeptable Verringerungen könnten entweder zu 1oder 0für Staaten führen, die zu führen n/a.

Mit dieser Einstellung, !(exists && isDirectory) ist noch eine gültige Reduzierung, die zu einem 1z !e && d.

Es !isDirectorywäre jedoch eine viel einfachere Reduzierung, die 0z !e && d.

zzzzBov
quelle
4
Der nächste Schritt ist zu realisieren, dass es darauf isDirectoryankommt exists. Es kann nicht gleichzeitig ein Verzeichnis sein und nicht existieren.
Christoffer Hammarström
@ChristofferHammarstrom, Außerhalb des Kontexts kann ich nicht davon ausgehen, dass sich die Variablen auf dasselbe beziehen, aber das ist ein gültiger Punkt. Die Ergebnisspalte sollte n/aan Stellen gefüllt werden, an denen der Zustand nicht erreicht werden kann, und die Gleichung sollte entsprechend reduziert werden.
zzzzBov
Wenn sich die Variablen auf zwei verschiedene Kontexte beziehen, sind sie zu knapp und müssen umbenannt werden.
Christoffer Hammarström
Aber eine Wahrheitstabelle zu erstellen und auszuwerten, ist NP-vollständig!
Thomas Eding
@ThomasEding, ich habe dann zwei Zitate für dich: "Theorie und Praxis sind gleich; in der Praxis sind sie nicht gleich." und "Vorzeitige Optimierung ist die Wurzel allen Übels."
zzzzBov
22

Zur besseren Lesbarkeit extrahiere ich gerne boolesche Bedingungen in Methoden:

if(fileNameUnused())
{...}

public boolean fileNameUnused() {
   return exists && !isDirectory || !exists;
}

Oder mit einem besseren Methodennamen. Wenn Sie diese Methode richtig benennen können, muss der Leser Ihres Codes nicht herausfinden, was die Boolesche Bedingung bedeutet.

Puckl
quelle
+1 für nützliche Namen. Aber irgendwo müssen Sie die Bedingung neu formatieren.
Apoorv Khurasia
4
Eine weniger extreme Alternative, die immer noch Absicht vermittelt, ist nur die verwendete Bedingung zu nennen:boolean fileNameUnused = !exists || !isDirectory; if (fileNameUnused) { doSomething(); }
Steven
8

Sie könnten einfach versuchen, den No-Go- Fall zu nageln und auszusteigen, wenn das auftaucht.

while(someCondition) {

    if(exists && isDirectory)
        continue;
        // maybe "break", depends on what you're after.

        // the rest of the code
}

oder auch

function processFile(someFile)
{ 
    // ...
    if(exists && isDirectory)
       return false;
    // the rest of the code
    // ...
}
ZJR
quelle
Werden break, continue und mehrere return-Anweisungen nicht als Code-Gerüche betrachtet?
Freiheit
8
@Freiheit Kommt auf den Kontext an. Manchmal wird eine Early Return-Anweisung verwendet, um Einrückungen zu reduzieren und so die Lesbarkeit zu verbessern.
Marco-Fiset
Beste Antwort: Komplexe Bedingungen verschwenden enorm viel Zeit damit, sie zu lesen und genau zu verstehen. Infolgedessen werden sie oft als gelesen betrachtet, was zu heimtückischen Fehlern führt.
Mattnz
6

Wie bereits erwähnt, können Sie eine Wahrheitstabelle verwenden. Der zweite Schritt könnte eine KV-Karte sein zur Minimierung der Anzahl der Begriffe sein.

Verwendung der Gesetze der Booleschen Algebra ist ein weiterer Ansatz:

A = existiert
B =! IsDirectory
! A =! Existiert

&& = *
|| = +

[Bearbeiten]
Eine einfachere Transformation, da die Operationen AND und OR sich gegenseitig verteilen:

existiert &&! isDirectory || ! existiert
= A * B +! A
= (A +! A) * (B +! A)
= 1 * (B +! A)
= B +! A
[/ Edit]

existiert &&! isDirectory || ! existiert
= A * B +! A
= A * B +! A * 1 // Identität
= A * B +! A * (B + 1) // Vernichter
= A * B +! A * B +! A / / Verteilung und Identität
= B * (A +! A) +! A // Verteilung
= B * 1 +! A // Ergänzung 2
= B +! A // Identität
=! IsDirectory || existiert

Oder mit doppeltem Komplement (!! x = x):

A * B +! A
= !! (A * B +! A)
=! (! (A * B) * A)
=! ((! A +! B) * A)
=! (! A * A + ! B * A)
=! (0 +! B * A)
=! (! B * A)
= B +! A
=! IsDirectory || existiert

Eddie Gasparian
quelle
+1 für die Verwendung von formalen Regeln (ich hätte nie gedacht, dass ich nach meinem ersten Studienjahr eine davon sehen würde).
Nemanja Boric
5

Ich benutze nicht gerne "!" wenn der Ausdruck mehr als eine Bedingung enthält. Ich werde Codezeilen hinzufügen, um die Lesbarkeit zu verbessern.

doesNotExist = !exists;
isFile = exists && !isDirecotry;
if (isFile || doesNotExist) 
   {}
David W
quelle
+1 Dies erleichtert das Auslesen als "ob es eine Datei gibt oder nicht", was der englischen Sprache viel näher kommt.
Phil
Dies ist ein Refactoring mit dem Namen Introduce Explaining Variable .
Eddie Gasparian
1

Wie bereits erwähnt, kann der Zustand auf Folgendes reduziert werden:

if (!(exists && isDirectory))

Ich wette jedoch, dass ein Verzeichnis Existenz impliziert. In diesem Fall können wir die Bedingung auf Folgendes reduzieren:

if (!isDirectory)
Jack Applin
quelle