2017-04-01 7 views
2

Dies ist eine abstrakte Frage, die keinen echten Code enthält (und vielleicht auch nicht den besten Pseudocode). Hoffentlich ist sie so bedeutungsvoll, dass sie nicht zu Tode moderiert wird. Aber es ist eine Frage, die sich immer wieder stellt, denn das Projekt, an dem ich arbeite, ist ein sehr linearer, von früheren Bedingungen abhängiger Prozess. So ...Sequenzielle Logik und Lesbarkeit

Angesichts einer Reihe von logischen Aufgaben, von denen jede von der vorhergehenden abhängt, habe ich versucht, zwei Möglichkeiten, den Code zu strukturieren. One hängt von einer proceed Variable, wie diese

Proceed = True 

If Task1 Not Successful Then 
    Proceed = False 
End If 

If Proceed Then 
    If Task2 Not Successful Then 
     Proceed = False 
    End If 
End If 

usw.

Aber ich habe in einer Reihe von Orten Kommentare zu dem Effekt gelesen, dass dieser Lauf Variable Ansatz Gehen ist nicht ideal. Also, alternativ kann ich

If Task1 Succcesful Then 
    If Task2 Successful 
     Then Etc 
    Else 
     Error Condition 
    End If 
Else 
    Error Condition 
End If 

In meinen Augen haben, die ehemalige viel besser lesbar ist, ist die Logik sehr offensichtlich. Und wenn die Anzahl der Aufgaben in der Sequenz groß wird (mehr als 3 oder wirklich), wird das verschachtelte Ifs wirklich unhandlich. Also, meine Frage ist, was ist der Grund dafür, diesen ersten Ansatz nicht zu verwenden? Und gibt es eine bessere Möglichkeit, die Logik im zweiten Beispiel zu strukturieren, um die Lesbarkeit zu verbessern? Oder gibt es einen dritten Weg, der sowohl die Probleme (was auch immer sie sind) mit ersterem, als auch die Lesbarkeitsprobleme der letzteren angeht? Oder ist der erste Ansatz eigentlich in Ordnung, wenn man tatsächlich eine Folge von sequentiell abhängigen Aufgaben hat?

Antwort

0

Es hängt wirklich von Ihrer Situation ab. Ohne weitere Details, und mit Code kleben, die streng äquivalent zu Ihrem ursprünglichen Block ist, würde ich durch die Vermeidung unnötiger Verschachtelung starten:

Proceed = False; 

if Task1 successful and Task2 successful Then 
    Proceed = True 
end if 

In den meisten Sprachen, können Sie einfach die Boolesche setzen gerade in die Variable.

Proceed = task1 successful and task2 successful 

Wenn Sie wirklich lieber zu vermeiden, und dann vielleicht so:

Proceed = True; 

If Task1 not successful then 
    Proceed = False 
Else if Task2 not successful then 
    Proceed = False 
Else if Task3 not successful then 
    Proceed = False 
End if 

In allen Fällen so weit, vermeiden Sie nisten. Für die Lesbarkeit ist dies wichtig.

Abgesehen davon hat Ihre Alternative zwei Änderungen. Erstens ist die "Fortfahren" Variable komplett weggelassen. Ich stimme dem zu. Was für ein Leser Ihrer ursprünglichen Code muss überwunden ist:

initialize x ... nun, wenn x dann y bereit ... Okay, jetzt tun y

Wenn Sie ändern können dies:

wenn x dann tun y

die konzeptionell einfacher ist.

So würde ich tun:

If Task1 successful and Task2 successful and Task3 successful then 
    Do your thing 
End if 

Oder

If Task1 not successful then 
    Do something 
else If Task2 not successful then 
    Do some other thing 
else 
    Do your main thing 
end if 

Der zweite Unterschied ist, dass Sie in „Fehlerzustand“ setzen. Insbesondere erwähnen Sie "Fehler". Wenn die Dokumente, die Sie gerade lesen, sagen, dass Sie die Fehler behandeln sollten (z. B. indem Sie die Ausführung stoppen und eine Fehlermeldung drucken), ist dies korrekt. Wenn Sie jedoch die Möglichkeit haben, sollten Sie mit ihnen umgehen, bevor Sie überhaupt zur if/then-Anweisung gelangen, wie zum Beispiel in der Task1-Prozedur. Dies vereinfacht nicht nur die if/then-Anweisung, sondern ist auch eine bessere Erfahrung für den Programmierer, da jede vernünftige IDE sie zum Scheitern führen wird, und es ist am besten, dass Sie den Fehler behandeln, sobald er auftritt, so dass der Entwickler hat keine lange Spur zu folgen, um zu sehen, was die ultimative Quelle war.

0

Beide sind üblich. Die erste ist besonders häufig, wenn sie mit einigen kohärenten API arbeiten, die mehrere Methoden erfordert in einer Sequenz aufgerufen werden:

API_THING *thing = NULL; 
API_RESULT result = CreateThing(&thing, ...); 
if (API_OK == result) result = InitializeThing(&thing, ...); 
if (API_OK == result) result = DoThingToThing(&thing, ...); 
// ... 
if (thing) 
{ 
    ReleaseThing(&thing, ...); 
    thing = NULL; 
} 

Die andere ist üblich, wenn Sie Nest brauchen nicht mehr als 2-3 Ebenen tief (vor allem, wenn beide Fälle behandelt werden):

eine andere, die nicht vorgeschlagen worden ist, ist goto und/oder Ausnahmen:

API_THING *thing = NULL; 
if (API_OK != CreateThing(&thing, ...)) goto CLEANUP; 
if (API_OK != InitializeThing(&thing, ...)) goto CLEANUP; 
if (API_OK != DoThingToThing(&thing, ...)) goto CLEANUP; 
//... 
CLEANUP: 
if (thing) 
{ 
    ReleaseThing(&thing, ...); 
    thing = NULL; 
} 

Wenn Ausnahmen verwenden Sie wie im goto Beispiel tun könnte über und auf jeder Linie werfen, oder du migst ht Ihre APIs in Methoden wickeln, die werfen:

void DoCreateThing(API_THING **thing, ...) 
{ 
    if (API_OK != CreateThing(thing, ...)) 
     throw new ApiException("CreateThing Failed!"); 
} 

//... 

API_THING *thing = NULL; 
try 
{ 
    DoCreateThing(&thing, ...); 
} 
catch (ApiException e) 
{ 
    // ... 
} 
// ... 
finally 
{ 
    if (thing) 
    { 
     ReleaseThing(&thing, ...); 
     thing = NULL; 
    } 
} 

nehmen Herz: Wenn Sie die Programmierung richtig machen, welche Entscheidung Sie hier vornehmen, werden nicht so wichtig wie, wie Sie dieses Stück Verhalten von Ihrem High-Level-Architektur kapseln .