So bestimmen Sie die Abstraktionsebenen


35

Ich habe heute ein Buch mit dem Titel "Clean Code" gelesen und bin auf einen Absatz gestoßen, in dem der Autor über die Abstraktionsebenen pro Funktion sprach. Er hat einen Code als niedrige / mittlere / hohe Abstraktionsebene klassifiziert.

Meine Frage ist, nach welchen Kriterien der Abstraktionsgrad bestimmt wird.

Ich zitiere den Absatz aus dem Buch:

Um sicherzustellen, dass unsere Funktionen „eine Sache“ tun, müssen wir sicherstellen, dass die Anweisungen in unserer Funktion alle auf derselben Abstraktionsebene sind. Es ist leicht zu erkennen, wie Listing 3-1 gegen diese Regel verstößt. Es gibt Konzepte auf einer sehr hohen Abstraktionsebene, wie z. B. getHtml (); andere, die sich auf einer mittleren Abstraktionsebene befinden, z. B .: String pagePathName = PathParser.render (pagePath); und noch andere, die bemerkenswert niedrig sind, wie: .append ("\ n").


Antworten:


27

Der Autor erklärt im Unterabschnitt "Code von oben nach unten lesen" des Abschnitts, in dem es um Abstraktionen geht (hierarchische Einrückung):

[...] wir möchten das Programm so lesen können, als wäre es eine Menge von TO- Absätzen, von denen jeder die aktuelle Abstraktionsebene beschreibt und auf nachfolgende TO- Absätze auf der nächsten Ebene verweist .

  • Um die Setups und Teardowns einzuschließen, schließen wir Setups ein, dann den Inhalt der Testseite und dann die Teardowns.
    • Um die Setups einzuschließen, schließen wir das Suite-Setup ein. Wenn dies eine Suite ist, schließen wir das reguläre Setup ein.
      • Um das Suite-Setup einzuschließen, durchsuchen wir die übergeordnete Hierarchie nach der Seite "SuiteSetUp" und fügen eine include-Anweisung mit dem Pfad dieser Seite hinzu.
        • Um die Eltern zu suchen ...

Der Code, der dazu passen würde, wäre ungefähr so:

public void CreateTestPage()
{
    IncludeSetups();
    IncludeTestPageContent();
    IncludeTeardowns();
}

public void IncludeSetups()
{
    if(this.IsSuite())
    {
        IncludeSuiteSetup();
    }

    IncludeRegularSetup();
}

public void IncludeSuiteSetup()
{
    var parentPage = FindParentSuitePage();

    // add include statement with the path of the parentPage
}

Und so weiter. Jedes Mal, wenn Sie die Funktionshierarchie vertiefen, sollten Sie die Abstraktionsebenen ändern. In dem obigen Beispiel IncludeSetups, IncludeTestPageContentund IncludeTeardownssind alle auf dem gleichen Niveau der Abstraktion.

In dem in dem Buch gegebenen Beispiel schlägt der Autor vor, die große Funktion in kleinere Funktionen aufzuteilen, die sehr spezifisch sind und nur eine Sache tun. Bei richtiger Vorgehensweise würde die überarbeitete Funktion den hier gezeigten Beispielen ähneln. (Die überarbeitete Version finden Sie in Listing 3-7 des Buches.)


10

Um diese Frage zu verstehen, muss man verstehen, was eine Abstraktion ist. (Ich bin zu faul, um eine formale Definition zu finden, daher bin ich mir sicher, dass ich bald fertig werde, aber hier geht es weiter ...) Eine Abstraktion ist, wenn Sie ein komplexes Thema oder eine Entität nehmen und die meisten Details verbergen während Sie die Funktionalität offenlegen, die immer noch die Essenz dieses Objekts definiert.

Ich glaube, das Beispiel, das das Buch dir gegeben hat, war ein Haus. Wenn Sie sich das Haus sehr genau ansehen, werden Sie feststellen, dass es aus Brettern, Nägeln, Fenstern, Türen besteht ... Aber eine Comiczeichnung eines Hauses neben einem Foto ist immer noch ein Haus, obwohl es fehlt viele dieser Details.

Gleiches gilt für Software. Wann immer Sie programmieren, wie im Buch empfohlen, müssen Sie Ihre Software als Ebenen betrachten. Ein gegebenes Programm kann leicht mehr als hundert Schichten haben. Unten finden Sie möglicherweise Assembly-Anweisungen, die auf einer CPU ausgeführt werden. Auf einer höheren Ebene werden diese Anweisungen möglicherweise zu Festplatten-E / A-Routinen kombiniert. Auf einer höheren Ebene müssen Sie nicht mit Festplatten-E / A arbeiten. O direkt, weil Sie Windows-Funktionen verwenden können, um eine Datei einfach zu öffnen / lesen / schreiben / suchen / schließen. Dies sind alles Abstraktionen, noch bevor Sie zu Ihrem eigenen Anwendungscode gelangen.

Innerhalb Ihres Codes werden die Abstraktionsebenen fortgesetzt. Möglicherweise verfügen Sie über Routinen zur Bearbeitung von Zeichenfolgen / Netzwerken / Daten auf niedrigerer Ebene. Auf einer höheren Ebene können Sie diese Routinen in Subsystemen kombinieren, die Benutzerverwaltung, Benutzeroberflächenebene und Datenbankzugriff definieren. Eine weitere Schicht dieser Subsysteme könnte zu Serverkomponenten zusammengefasst werden, die Teil eines größeren Unternehmenssystems werden.

Der Schlüssel zu jeder dieser Abstraktionsebenen besteht darin, dass jede die Details der vorherigen Ebene (n) verbirgt und eine sehr saubere Schnittstelle darstellt, die von der nächsten Ebene verwendet werden kann. Um eine Datei zu öffnen, müssen Sie nicht wissen, wie einzelne Sektoren geschrieben werden oder welche Hardware-Interrupts verarbeitet werden müssen. Wenn Sie jedoch beginnen, die Abstraktionsschichtenkette zu durchlaufen, können Sie den Funktionsaufruf Write () bis hinunter zu den genauen Anweisungen verfolgen, die an den Festplattencontroller gesendet werden.

Der Autor fordert Sie auf, beim Definieren einer Klasse oder Funktion zu überlegen, welche Ebene Sie sind. Wenn Sie eine Klasse haben, die Subsysteme und Benutzerobjekte verwaltet, sollte dieselbe Klasse keine einfache Manipulation von Zeichenfolgen durchführen oder eine ganze Reihe von Variablen enthalten, nur um Socket-Aufrufe auszuführen. Dies wäre die Verletzung der Überkreuzung von Abstraktionsebenen und der Tatsache, dass eine Klasse / Funktion nur eine Aufgabe erfüllt (SRP - Single Responsibility Principle).


2

Meine Frage ist, nach welchen Kriterien der Abstraktionsgrad bestimmt wird.

Die Abstraktionsebene soll offensichtlich sein. Es ist abstrakt, wenn es Teil der Problemdomäne ist - nicht Teil der Programmiersprache. Es ist schwer klarer zu sein als "hoch abstrakt" == "nicht real" == "Problemdomäne". Und "nicht abstrakter == konkreter == Teil der Sprache". Es sollte trivial sein, die Abstraktionsebene zu bestimmen. Es sollte überhaupt keine Subtilität geben.

.append("\n")ist nicht abstrakt. Es wird lediglich ein Zeichen in eine Zeichenfolge eingefügt. Das wäre konkret. Nicht abstrakt.

String pagePathName = PathParser.render(pagePath);befasst sich mit Strings. Konkrete Dinge. Teilweise auf konkreten Programmiersprachen-Features. Teilweise arbeiten mit abstrakten "Pfad" - und "Parser" -Konzepten.

getHtml(); Abstrakt. Beschäftigt sich mit "Markup" und Dingen, die keine trivialen, konkreten Sprachfunktionen sind.

Abstract == kein Sprachmerkmal.

Konkret == ein Sprachmerkmal.


1
Wenn Sie abstrakt als eine Eigenschaft definieren, die die Dinge beschreibt, die ein Programmierer erstellt, dh vom Programmierer erzeugte Abstraktionen, dann bin ich geneigt, Ihren Wortdefinitionen zuzustimmen. Aber alle Programmiersprachen sind Abstraktionen über etwas Konkreteres. Die Wahl der Programmiersprache bestimmt in hohem Maße, auf welcher Abstraktionsebene Sie beginnen.
Robert Harvey

1

Ich denke, die Abstraktionsebene ist einfach ... Wenn die Codezeile nicht direkt die einzelne Verantwortung der Methode implementiert, handelt es sich um eine andere Abstraktionsebene. Wenn mein Methodenname beispielsweise SaveChangedCustomers () lautet und eine Liste ALLER Kunden als Parameter verwendet, besteht die einzige Verantwortung darin, alle Kunden in der Liste zu speichern, die geändert wurden:

foreach(var customer in allCustomers)
{
    if (CustomerIsChanged(customer)
        customer.Save();
}

Anstatt die CustomerIsChanged () -Methode aufzurufen, wird häufig die Logik zum Ermitteln, ob sich der Kunde geändert hat, in die foreach-Schleife eingebettet. Es liegt NICHT in der Verantwortung dieser Methode, festzustellen, ob sich der Kundendatensatz geändert hat! Es ist eine andere Abstraktionsebene. Aber was ist, wenn die Logik für diese Bestimmung nur eine Codezeile ist? Es ist egal !!! Es ist eine andere Abstraktionsebene und muss außerhalb dieser Methode liegen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.