Freitag, 18. April 2014

Abstraktheit - das Konzept

Um die Brücke zum Stable Abstractions Prinzip (SAP) schlagen zu können, müssen wir uns zunächst dem Konzept der Abstraktheit widmen, das Martin hier im Sinn hat. Ohne der detaillierten Prinzipien-Beschreibung bereits allzu sehr vorwegzugreifen, sei das SAP hier in seiner allgemeinen Form zitiert:
"Eine Komponente sollte so abstrakt sein, wie sie stabil ist." [Martin2002]
Es ist auch hier (wie für die Stabilität) möglich, das Konzept auf sehr konkrete Metriken zu beziehen oder es allgemeiner zu betrachten. Für die metrische Betrachtung werde ich im nächsten Blogartikel Martins Abstraktheits-Metrik behandeln. Hier werde ich zunächst erläutern, was Martin mit Abstraktheit meint und worin seine Motivation besteht, wenn er einen Zusammenhang zwischen Abstraktheit und Stabilität herstellt.

Eigentlich geht es um Entkopplung

Abstraktheit ermöglicht nach Martins Verständnis vor allem die Anwendung des Open-Closed-Prinzips. Der Klient eines abstrakten Typs weiß nicht, welche konkrete Instanz er tatsächlich verwendet - die Abstraktheit des Typs entkoppelt ihn vom konkreten Typ der Instanz. Während der abstrakte Typ stabil (closed - geschlossen für Änderung) bleibt, ist die konkrete Instanz veränderlich (open - offen für Erweiterung). Genau dies ist Martins Ziel: Trotz der hohen Stabilität noch eine gewisse Flexibilität zu bewahren. Er schreibt:
"A stable component should also be abstract so that its stability does not prevent it from being extended." [Martin2002]
Nun wird deutlicher, dass es eigentlich nicht um Abstraktheit geht, sondern Entkopplung. Um zu erreichen, was Martin möchte, müsste der Klient in einer Sprache wie Java nicht notwendigerweise einen abstrakten Typ verwenden, sondern es könnte sich auch um eine Standardimplementierung (also um eine konkrete Klasse) handeln. Solange diese nicht final deklariert ist und die relevanten Methoden überschrieben werden können (d. h. sie sind ebenfalls nicht final deklariert und mindestens protected), ermöglicht auch dies eine Anwendung des Open Closed-Prinzips. In C++, das Martin bevorzugt im Blick hatte, ist dies etwas anders, da hier die relevanten Methoden explizit als virtual deklariert werden müssen. Das Konzept der abstrakten Klasse fällt hier mit virtuellen Methoden zusammen, während in Java alle Methoden virtuell sind und folglich auch keine Notwendigkeit zur Nutzung abstrakter Klassen besteht, um die Klasse offen für Erweiterungen (durch Subklassenbildung und Überschreiben von Methoden) zu halten.

Entkopplung durch Abstraktion ist häufig sinnvoll

Es macht freilich dennoch häufig Sinn, an Stelle einer Standardimplementierung eine Abstraktion zu verwenden, sei es eine abstrakte Klasse oder ein Interface. Aus der Sicht des Klienten ist damit jederzeit deutlich, dass keine Abhängigkeit von einer konkreten Realisierung existiert und dass man sich nicht auf das Verhalten irgendeiner konkreten Realisierung verlassen darf. Entscheidend ist allein die öffentliche Schnittstelle der Abstraktion. Zudem ist klar, dass irgendwo (in der Regel per Dependency Injection) eine Entscheidung getroffen werden muss, welche Instanz tatsächlich an den Klienten übergeben wird.

Wir halten aber dennoch fest: Um stabile Komponenten offen für Erweiterung zu halten, müssen diese nicht in allen objektorientierten Sprachen auch abstrakt sein. Insofern führt bereits Martins Ausgangspunkt in die Irre.

Quellen

[Martin2002] - Agile Principles, Patterns, and Practices in C#, Robert C. Martin (2002)