Abstrakte Klassen und Interfaces
https://bildung.social/@oerinformatik/
https://oer-informatik.de/uml-klassendiagramm-interface-abstraktion
tl/dr; (ca. 8 min Lesezeit): Ein großes Problem bei Objekt- und Klassenbeziehung ist die starke Kopplung unterschiedlicher Klassen aneinander. Der Austausch von Verhalten ist so nur mit großem Aufwand möglich. Das Konzept der Abstraktion bietet hier in Form von abstrakten Klassen und Interfaces die Möglichkeit, Komponenten lose zu koppeln. (Zuletzt geändert am 24.05.2023)
Dieser Text ist ein Teil der Infotext-Serie zu UML-Klassendiagrammen:
Abstrakte Klassen
Wozu abstrakte Klassen dienen soll an folgendem Beispiel erläutert werden: es soll das gesamte Vermögen, das in Aktien, auf Konten und als Festgeld angelegt ist, jederzeit ausgewertet werden können. Dazu sollen die Klassen Konto
, Aktien
und Festgeld
von einer gemeinsamen Elternklasse Investment
erben, in der festgelegt ist, dass wir über die Methode getGuthaben()
immer den aktuellen Zeitwert des Investments erhalten.

Da das Guthaben zum Zeitwert beim Konto
schlicht über den Kontostand, beim Festgeld
über die Verzinsung der Einlage und bei einer Aktie
über den aktuellen Börsenwert ermittelt werden muss, kann die Methode getGuthaben()
nicht sinnvoll zentral in Investment
implementiert werden. Wir können verdeutlichen, dass jede Unterklasse eine eigene Implementierung benötigt, in dem wir den Methodenrumpf leer lassen und lediglich die Signatur und der Rückgabewert festlegen: derlei Methoden nennt man abstrakt.
Durch die fehlende Implementierung von getGuthaben()
ist das Verhalten eines Investment
nicht vollständig definiert - es können keine konkreten Instanzen von Investment
gebildet werden. Investment
ist ebenso abstrakt.
Im UML-Klassendiagramm werden abstrakte Klassen und Methoden durch kursive Schreibweise gekennzeichnet:

Die einzelnen Kindklassen müssen die Methode getGuthaben()
implementieren, damit sie selbst konkrete Klassen sind, die instanziiert werden können:

Die kursive Schreibweise kann schnell übersehen werden, daher ist es ratsam, zusätzlich das Schlüsselwort {abstract}
als constraint in geschweiften Klammern unterhalb des Klassennamens zu notieren.

In der Regel werden zwar nur Klassen mit abstrakten Methoden selbst als abstrakt dargestellt, theoretisch kann jedoch jede Klasse als abstrakt gekennzeichnet werden, auch wenn sie instanziierbar wäre. Umgekehrt gilt jedoch:
Sobald eine Klasse über mindestens eine abstrakte Methode verfügt muss sie als abstrakt gekennzeichnet werden.
Alle Klassen, die nicht instanziiert werden können oder sollen, werden abstrakt genannt. Alle Klassen, die instanziiert werden können oder sollen, werden konkrete Klassen genannt.
Abstrakte Klassen können alle Member und Eigenschaften enthalten, die auch konkrete Klassen enthalten können.
Interfaces
Das Konzept der Abstraktion wird mit Interfaces weiterentwickelt: Interfaces stellen abstrakte Strukturen dar, die im engeren Sinn komplett frei von Implementierung sind. Im Kern legen Interfaces lediglich Methodensignaturen und Rückgabewerte fest.
Interfaces stellen Verträge zwischen Klassen dar, die festschreiben, welche Methoden eine Klasse implementieren muss.

verrechneJahreszinsen()
implementiert werden mussInterfaces werden im UML-Diagramm wie Klassen dargestellt, die mit dem Stereotyp <<Interface>>
oberhalb des Namens notiert werden.
Klassen, die die abstrakten des Interfaces implementieren, werden mit einer nicht ausgefüllten Pfeilspitze in Richtung Interface (analog der Vererbung) und einer gestrichelten Linie verbunden:

Sparbuch
implementiert Verzinsbar
(und somit verrechneJahreszinsen()
)Sofern die Klassen die abstrakten Methoden eines Interfaces nicht selbst implementieren sind die Klassen selbst abstrakt.
Die Grenzen zu abstrakten Klassen sind in den unterschiedlichen Programmiersprachen unterschiedlich stark ausgeprägt. So können Interfaces auch Attribute beinhalten.
In Java gelten beispielsweise folgende Regeln:
Interfaces können statische Attribute enthalten
Interfaces können default-Implementierungen enthalten
Benutzen von Interfaces und Implementieren von Interfaces: Dependency Inversion Principle
Interfaces werden zur losen Kopplung zwischen Klassen genutzt. Häufig hängen Klassen über Assoziationen direkt von der Implementierung anderer Klassen ab. Im folgenden Beispiel benötigt die Klasse Kunde
ein Objekt vom Typ Konto
, um einen Artikel zahlen zu können:

Änderungen an Konto
können somit unmittelbar dazu führen, dass sich auch Kunde
ändern muss. Das ist insbesondere dann nicht wünschenswert, wenn sich beide in unterschiedlichen Modulen befinden (da Kunde
Konto
nutzt wäre es z.B. denkbar, dass sich dieses in einem Modul höheren Abstraktionsniveaus befindet).
An die Stelle der direkten Abhängigkeit tritt ein Vertrag zwischen Kunde
und Konto
: Die Abhängigkeit besteht darin, dass es die Methoden abbuchen()
und einzahlen()
geben muss: Kunde
will diese Nutzen, und das Objekt, das Kunde
nutzt, muss diese Methoden bereitstellen:

Solange das Interface unverändert bleibt, können die jeweiligen Implementierungen geändert, ja sogar getauscht werden: Kunde hängt nur noch von der abstrakten Struktur Buchbar
ab, aber nicht mehr von einer konkreten Implementierung. Realisiert werden kann diese Abhängigkeit auch über andere Implementierungen von Buchbar
.

Kunde nutzt ein Objekt vom Typ Buchbar
, um einen Artikel zu bezahlen (siehe Auszug aus der Methode bezahlen()
).
Lollipop- / Ball-and-Socket-Notation
Wenn der Aufbau des Interfaces nicht so wichtig ist wird häufig die Lollipop- (oder Ball and Socket-) Notation gewählt, die nur die Schnittstelle benennt, die Member des Interface aber nicht zeigt:

Bei Kunde ist mit der stilisierten Buchse gekennzeichnet, dass ein Buchbar
-Objekt benötigt wird. Konto
stellt dieses Objekt zur Verfügung, war durch den stilisierten Stecker dargestellt wird.
Links und weitere Informationen
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Abstrakte Klassen und Interfaces” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/uml-klassendiagramm-interface-abstraktion veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/uml/umlklasse. Stand: 24.05.2023.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]