Objektorientierte Modellierung und Programmierung
Eine Schulbibliothek verwaltet Bücher und Leser. Ein Buch hat einen Titel und ist verliehen oder nicht, die Bibliothek kennt ihre Bücher, ein Leser leiht Bücher aus. Wer das Programm später erweitern muss, braucht eine Gliederung: Welche Klassen gibt es? Wer darf welche Daten ändern? Wie hängen die Klassen zusammen, und wie hält man das fest, bevor man programmiert?
Du lernst, ein System aus Objekten zu entwerfen: Referenzen, Kapselung, Beziehungen zwischen Klassen, UML-Diagramme und Regeln für einen guten Entwurf. Die Beispiele sind in Python.
Objekt, Klasse, Attribut, Methode und Konstruktor
Ein Objekt hat einen Zustand (die Werte seiner Attribute), ein Verhalten (seine Methoden) und eine Identität: Zwei Objekte sind verschieden, auch wenn alle Attributwerte gleich sind. Eine Klasse legt Attribute und Methoden für alle ihre Objekte fest. Der Konstruktor läuft beim Erzeugen eines Objekts und setzt den Anfangszustand. In Python heißt er , und ist das Objekt, das die Methode aufgerufen hat.
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 1 | 0 | |
| 2 | 1 | |
| 3 | 2 | |
| 4 | 2 | |
| 5 | 1 | |
| 6 | 2 | |
| 7 | 1 | |
| 8 | 2 | |
| 9 | 3 | |
| 10 | 2 | |
| 11 | 2 |
erzeugt ein Objekt. sendet ihm die Nachricht .
Referenz
Eine Variable, die ein Objekt trägt, enthält nur eine Referenz, einen Verweis auf das Objekt. kopiert den Verweis, nicht das Objekt (Aliasing): Beide Namen führen zum selben Objekt. bedeutet „kein Objekt“, und bricht mit einem Fehler ab. Der Operator prüft, ob es dasselbe Objekt ist, prüft Gleichheit, die eine Klasse selbst festlegen kann.
Zugriffsmodifikatoren, Kapselung und Geheimnisprinzip
Ein Zugriffsmodifikator legt fest, wer ein Attribut oder eine Methode benutzen darf:
| Sichtbarkeit | UML | Java | Python |
|---|---|---|---|
| öffentlich | + | public | kein Unterstrich |
| geschützt (Klasse und Unterklassen) | # | protected | ein Unterstrich, nur Vereinbarung |
| privat (nur die Klasse selbst) | - | private | zwei Unterstriche (Namensverschleierung), kein echter Schutz |
Kapselung heißt: Der Zustand eines Objekts ist privat, Zugriffe laufen über öffentliche Methoden. Das Geheimnisprinzip geht weiter: Nutzer kennen nur die Schnittstelle, also die öffentlichen Methoden und was sie leisten, nicht die innere Darstellung. Dann lässt sich die Darstellung ändern, etwa ein Guthaben statt in Euro in Cent speichern, ohne fremden Code anzupassen. Eine Getter-Methode liest ein Attribut, eine Setter-Methode setzt es und kann Werte prüfen, bevor sie gespeichert werden. Wer aber für jedes Attribut einen Getter und einen Setter anbietet, gibt die innere Darstellung doch preis.
Assoziation, Aggregation und Komposition
Die Multiplizität am Ende einer Beziehung gibt an, wie viele Objekte beteiligt sind: genau eins, höchstens eins, beliebig viele (auch keins), mindestens eins.
| Beziehung | Bedeutung | UML | Beispiel |
|---|---|---|---|
| Assoziation | Objekte kennen oder nutzen einander | Linie mit Multiplizitäten | Leser 0..1 und Buch *: Ein Buch ist an höchstens einen Leser verliehen, ein Leser hat beliebig viele Bücher |
| Aggregation | Teil und Ganzes, die Teile gibt es auch ohne das Ganze | Linie mit hohler Raute am Ganzen | Bibliothek und Buch: Ein Buch kann in eine andere Bibliothek wechseln |
| Komposition | Teil und Ganzes, der Teil gehört genau einem Ganzen und endet mit ihm | Linie mit ausgefüllter Raute am Ganzen | Buch und Kapitel: Ohne das Buch gibt es seine Kapitel nicht mehr |
In Python steht eine Beziehung als Attribut, das auf Objekte verweist, zum Beispiel in der Bibliothek.
UML-Klassendiagramm und Sequenzdiagramm
Ein Klassendiagramm zeigt jede Klasse als Rechteck mit drei Fächern (Name, Attribute, Methoden) und die Beziehungen zwischen den Klassen. Einträge schreibt man als oder . Die Klasse Buch hat also , , und . Von Bibliothek führt eine Linie mit hohler Raute zu Buch, am Buch-Ende steht .
Ein Sequenzdiagramm zeigt, in welcher Reihenfolge Objekte einander Nachrichten senden. Jedes Objekt hat oben ein Rechteck und darunter eine senkrechte Lebenslinie. Die Zeit läuft von oben nach unten. Ein Pfeil zwischen zwei Lebenslinien ist ein Methodenaufruf, ein gestrichelter Pfeil zurück ist die Rückgabe.
Objekte in Feldern und Listen
Objekte lassen sich in einem Feld (feste Länge, Zugriff über den Index) oder einer Liste (veränderliche Länge) sammeln. Das Feld enthält Referenzen, nicht die Objekte selbst. Eine Schleife sendet jedem Element dieselbe Nachricht. Verändert man ein Objekt über die Schleifenvariable, ändert man das Objekt in der Liste, denn beide verweisen auf dasselbe.
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 12 | 0 | |
| 13 | 1 | |
| 14 | 2 | |
| 15 | 1 | |
| 16 | 2 | |
| 17 | 1 | |
| 18 | 2 | |
| 19 | 2 | |
| 20 | 3 | |
| 21 | 4 | |
| 22 | 2 |
Bibliothek: Ablauf und Sequenz
Bibliothek: Ablauf und Sequenz
Es gilt , und . Dann laufen , , , und . Was wird ausgegeben, und wie läuft der letzte Aufruf als Sequenz ab?
Das erste setzt verliehen auf True und gibt True zurück. Das zweite findet verliehen schon True vor und gibt False zurück, also ist ok gleich False. Beim Zählen sendet die Bibliothek jedem Buch der Liste eine Nachricht:
| Nr. | Sender | Empfänger | Nachricht |
|---|---|---|---|
| 1 | Aufrufer | bib : Bibliothek | |
| 2 | bib | b1 : Buch | |
| 3 | b1 | bib | Rückgabe True |
| 4 | bib | b2 : Buch | |
| 5 | b2 | bib | Rückgabe False |
| 6 | bib | Aufrufer | Rückgabe 1 |
Nur b2 ist nicht verliehen, also ist n gleich 1. Die Ausgabe ist 1 False.
Klassenentwurf: Kohäsion und Kopplung
Zwei Maße beurteilen einen Entwurf. Die Kohäsion misst, wie eng die Aufgaben innerhalb einer Klasse zusammengehören. Sie soll hoch sein: Eine Klasse hat eine klar umrissene Verantwortung. Die Kopplung misst, wie stark Klassen voneinander abhängen. Sie soll lose sein: Eine Klasse kennt wenige andere und nur deren Schnittstelle.
Eine Klasse Konto, die auch Kontoauszüge formatiert und E-Mails verschickt, hat niedrige Kohäsion, und jede Änderung am Mailversand zwingt zum Ändern von Konto. Besser sind getrennte Klassen für Konto, Kontoauszug und Mailversand. Greift eine Klasse direkt auf Attribute einer anderen zu, ist die Kopplung eng: Jede Änderung der inneren Darstellung wirkt sich dort aus.
Eine Liste mit Malzeichen füllen
Eine Liste mit Malzeichen füllen
„ erzeugt drei Bücher.“
Der Konstruktor läuft nur einmal. Die Liste enthält drei Verweise auf dasselbe Objekt, wer eines ausleiht, hat alle ausgeliehen. Drei Objekte entstehen nur durch drei Konstruktoraufrufe, etwa in einer Schleife mit .
Kapselung bedeutet Getter und Setter für alles
Kapselung bedeutet Getter und Setter für alles
„Kapselung heißt: Alle Attribute sind privat, und jedes bekommt einen Getter und einen Setter.“
Dann ist die innere Darstellung über die Methoden wieder frei zugänglich, und das Geheimnisprinzip ist verletzt. Eine gekapselte Klasse bietet Operationen an, die zu ihrer Aufgabe passen, etwa .
Zusammenfassung
Ein Objekt hat Zustand, Verhalten und Identität. Der Konstruktor setzt den Anfangszustand.
Eine Objektvariable enthält eine Referenz. Eine Zuweisung kopiert den Verweis, prüft Identität.
Kapselung: Zustand privat, Zugriff über Methoden. Geheimnisprinzip: Nutzer kennen nur die Schnittstelle.
Assoziation verbindet Objekte. Aggregation und Komposition sind Teil-Ganzes-Beziehungen, bei der Komposition endet der Teil mit dem Ganzen.
Das Klassendiagramm zeigt Klassen, Beziehungen und Multiplizitäten, das Sequenzdiagramm die Folge der Nachrichten.
Felder und Listen enthalten Referenzen auf Objekte.
Guter Entwurf: hohe Kohäsion in den Klassen, lose Kopplung zwischen ihnen.
Übungen
Die Bibliothek enthält die vier Bücher b1, b2, b3 und b4. Es laufen , , und . Welche Zahl gibt danach zurück?
Ein Gebäude besteht aus Räumen. Wird das Gebäude abgerissen, gibt es die Räume nicht mehr. Wie modelliert man das?
Welche Klasse hat hohe Kohäsion?
Es läuft , dann . Bei wie vielen der drei Listeneinträge liefert danach False?
Die Klasse Schueler hat ein öffentliches Attribut note. Ein anderes Programmteil setzt , obwohl nur 1 bis 6 gültig sind. Erkläre, wie Kapselung das verhindert, und gib die Methode an.