Dieser Begriff von Single Entry, Single Exit (SESE) stammt aus Sprachen mit expliziter Ressourcenverwaltung wie C und Assembly. In C verliert Code wie dieser Ressourcen:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
In solchen Sprachen haben Sie grundsätzlich drei Möglichkeiten:
Replizieren Sie den Bereinigungscode.
Pfui. Redundanz ist immer schlecht.
Verwenden Sie a goto
, um zum Bereinigungscode zu springen.
Dies erfordert, dass der Bereinigungscode das Letzte in der Funktion ist. (Und deshalb argumentieren einige, dass goto
es seinen Platz hat. Und es hat in der Tat - in C.)
Führen Sie eine lokale Variable ein und manipulieren Sie den Steuerungsfluss.
Der Nachteil ist , dass Steuerfluss durch Syntax manipuliert (denken break
, return
, if
, while
) ist viel einfacher als durch den Zustand der Variablen manipulierte Steuerfluss zu folgen (da diese Variablen haben keinen Zustand , wenn Sie auf dem Algorithmus aussehen).
In der Montage ist es noch seltsamer, weil Sie zu jeder Adresse in einer Funktion springen können, wenn Sie diese Funktion aufrufen, was praktisch bedeutet, dass Sie eine nahezu unbegrenzte Anzahl von Eintrittspunkten für jede Funktion haben. (Manchmal ist dies hilfreich. Solche Thunks sind eine übliche Technik für Compiler, um die this
Zeigeranpassung zu implementieren, die zum Aufrufen von virtual
Funktionen in Mehrfachvererbungsszenarios in C ++ erforderlich ist .)
Wenn Sie Ressourcen manuell verwalten müssen, führt das Ausnutzen der Optionen zum Aufrufen oder Verlassen einer Funktion zu komplexerem Code und damit zu Fehlern. Daher erschien eine Denkschule, die SESE propagierte, um saubereren Code und weniger Bugs zu erhalten.
Wenn jedoch eine Sprache Ausnahmen aufweist, kann (fast) jede Funktion zu (fast) jedem Zeitpunkt vorzeitig beendet werden. Daher müssen Sie ohnehin Vorkehrungen für eine vorzeitige Rückkehr treffen. (Ich denke, dies finally
wird hauptsächlich in Java und using
(bei der Implementierung IDisposable
, finally
ansonsten) in C # verwendet; C ++ verwendet stattdessen RAII .) Wenn Sie dies getan haben, können Sie es nicht versäumen, aufgrund einer frühen return
Aussage nach sich aufzuräumen das stärkste Argument für SESE ist verschwunden.
Damit bleibt die Lesbarkeit. Natürlich ist eine 200-LoC-Funktion mit einem halben Dutzend return
zufällig darüber gestreuten Anweisungen kein guter Programmierstil und ergibt keinen lesbaren Code. Aber eine solche Funktion wäre auch ohne diese vorzeitigen Erträge nicht leicht zu verstehen.
In Sprachen, in denen Ressourcen nicht manuell verwaltet werden oder verwaltet werden sollten, ist die Einhaltung der alten SESE-Konvention wenig oder gar nicht sinnvoll. OTOH, wie ich oben dargelegt habe, macht SESE Code oft komplexer . Es ist ein Dinosaurier, der (mit Ausnahme von C) nicht gut in die meisten heutigen Sprachen passt. Anstatt die Verständlichkeit des Codes zu verbessern, behindert es ihn.
Warum halten Java-Programmierer daran fest? Ich weiß es nicht, aber von meinem (externen) POV aus hat Java eine Menge Konventionen von C übernommen (wo sie Sinn machen) und sie auf seine OO-Welt angewendet (wo sie nutzlos oder ausgesprochen schlecht sind), wo sie sich jetzt festhalten sie, egal was die Kosten. (Wie die Konvention, alle Variablen am Anfang des Gültigkeitsbereichs zu definieren.)
Programmierer halten aus irrationalen Gründen an allerlei merkwürdigen Notationen fest. (Tief verschachtelte strukturelle Aussagen - "Pfeilspitzen" - wurden in Sprachen wie Pascal einst als schöner Code angesehen.) Eine logische Argumentation scheint die Mehrheit von ihnen nicht davon zu überzeugen, von ihren etablierten Methoden abzuweichen. Der beste Weg, solche Gewohnheiten zu ändern, ist wahrscheinlich, sie früh zu lehren, das Beste und nicht das Konventionelle zu tun. Als Programmierlehrer haben Sie es in der Hand.:)