Als Aggregation wird das Zusammenfassen
mehrerer Objekte zu neuen bezeichnet. Wir haben bereits ein Beispiel dafür
gesehen: Die Bruch
-Klasse fasst einen Zähler und einen Nenner zu einem neuen
Wert zusammen. Die Bestandteile sind ihrerseits jeweils als Zahl-Objekte
representiert. In ähnlicher Weise könnten wir mehrere Zahlen zu Punkten in einem
Koordinatensystem zusammen fassen, mehrere Punkte zu geometrischen Figuren und
mehrere geometrische Figuren zu Bildern. Auf diese Weise entstehen immer
komplexere, hierarchische Daten auf Basis von einfacheren.
Wir wollen im folgenden den bereits verwendeten Mechanismus der Aggregation vertiefen und dann darauf aufbauend das neue Konzept der Vererbung kennenlernen.
Dazu definieren wir eine
Klasse Point
zur Darstellung von Punkten in einem
Koordinatensystem.
class Point:
def __init__(self, x, y):
self._x = x
self._y = y
Die Methode __init__
konstruiert einen Punkt aus einer x- und
einer y-Koordinate, indem entsprechende Parameter x
und y
in
Instanzvariablen _x
und _y
(auch Attributvariablen genannt) abgespeichert werden.
Durch die Benennung mit einem Unterstrich signalisieren wir,
dass außerhalb der Klassendefinition kein Zugriff
auf die Instanzvariablen erfolgen soll.
Um von außen lesenden Zugriff auf die Koordinaten zu erlauben,
definieren wir innerhalb der Klasse Point
Methoden x
und y
, die
die Werte der entsprechenden Koordinaten zurück liefern.
def x(self):
return self._x
def y(self):
return self._y
Um auch schreibenden Zugriff zu erlauben, definieren wir
(mutierende!) Methoden set_x
und set_y
, die die Koordinaten auf
übergebene Werte setzen.1
def set_x(self, x):
self._x = x
def set_y(self, y):
self._y = y
Dass der Zugriff auf Attribute, die in Klassen für Objekte definiert sind, nur über bereitgestellte Methoden erfolgt, ist ein Ausdruck von Datenkapselung. Ein Vorteil der Datenkapselung ist es, dass wir den Zugriff einschränken können. Zum Beispiel können wir testen, ob die übergebene Koordinate eine ganze Zahl ist, und nur in disem Fall den aktuellen Wert überschreiben. Dazu verändern wir die Methoden zum Setzen der Koordinaten wie folgt.
def set_x(self, x):
if type(x) == int:
self._x = x
def set_y(self, y):
if type(y) == int:
self._y = y
Eine solche Überprüfung erscheint auch bei der Konstruktion von Punkten sinnvoll. Dazu können wir die gerade definierten Methoden im Konstruktor verwenden, dessen Implementierung wir also wie folgt verändern.
def __init__(self, x, y):
self.set_x(x)
self.set_y(y)
Als nächstes definieren wir eine Klasse Shape
zur Darstellung geometrischer
Figuren, die als Zustand einen Punkt kapselt, der angibt, wo die Figur
gezeichnet werden soll.
class Shape:
def __init__(self, point):
self.set_location(point)
def location(self):
return self._location
def set_location(self, point):
if type(point) == Point:
self._location = point
Auch hier definieren wir Methoden zum lesenden und schreibenden
Zugriff auf den internen Zustand der Shape
-Objekte. Wir werden
später noch weitere Methoden für Shape
-Objekte definieren. Zunächst
jedoch definieren wir spezielle geometrische Figuren als sogenannte
Unterklassen der Klasse Shape
.
Diese Art Zugriffsmethoden zu definieren ist in Python unüblich. Eine Diskussion von Property-Decorators würde uns aber vom Wesentlichen ablenken. ↩︎