In der objektorientierten Programmierung kommunizieren Objekte miteinander, indem sie sich Botschaften (engl. messages) senden.
Eine Botschaft besteht im Wesentlichen aus einem Methodenaufruf an ein Objekt oder eine Klasse.
Beispiele
auto.beschleunigen(10); sonne.changeSize(120); double wurzel = Math.sqrt(45);
Die beiden ersten Beispiele stehen für sogenannte Instanzbotschaften - sie richten sich an eine Instanz einer Klasse, also an ein Objekt.
Das dritte Beispiel ist dagegen eine Klassenbotschaft. Hier wird die statische Methode einer Klasse wie Math aufgerufen. Ein Objekt dieser Klasse muss dazu nicht vorher angelegt werden.
Sender, Empfänger, Bezeichner und Argumente
Eine Botschaft zeichnet sich durch einen Sender (engl. Sender), einen Empfänger (Receiver), dem Bezeichner (Selector) und den Argumenten (Arguments) aus. Das möchte ich anhand der beiden obigen Beispiele näher erläutern.
auto.beschleunigen(10);
- Sender: das aufrufende Objekt
- Empfänger: das Objekt auto der Klasse Auto
- Bezeichner: die Methode beschleunigen()
- Argumente: der aktuelle Parameter 10
sonne.changeSize(120);
- Sender: das aufrufende Objekt, zum Beispiel ein Objekt der Klasse Zeichnung
- Empfänger: das Objekt sonne der Klasse Circle
- Bezeichner: die Methode changeSize()
- Argumente: der aktuelle Parameter 120
Die Denkweise
Die Denkweise mit den Botschaften stammt aus frühen OOP-Sprachen wie Smalltalk und betont die Kommunikation und Interaktion zwischen autonomen Objekten, anstatt nur eine lineare Abfolge von Befehlen zu sehen. In der Didaktik wird dieses Konzept noch häufig angewendet, beispielsweise auch immer wieder im Zentralabitur Informatik in NRW.
Vorteile dieses Konzepts
Die Betrachtung von Methodenaufrufen als Botschaften ist mehr als nur eine sprachliche Feinheit oder eine didaktische Überlegung. Das Konzept der Botschaft untermauert die grundlegenden Prinzipien der OOP und führt zu besserem Softwaredesign.
Förderung der Datenkapselung
Der Kern des Botschaft-Konzepts ist die Trennung von "Was" und "Wie":
Ein Sender-Objekt muss nur wissen, welche Botschaften ein Empfänger-Objekt versteht. Dies ist über seine öffentliches Schnittstelle bzw. die Signatur der Methoden geregelt.
Der Sender muss aber nicht wissen, wie der Empfänger die Botschaft intern verarbeitet.
Eine beliebte Analogie ist der An-Knopf einer Fernbedienung. Wenn man auf diesen Knopf drückt, sendet man eine Botschaft an den Fernseher. Wie der Fernseher intern aufgebaut ist und welche Schaltkreise aktiviert werden, wenn er angestellt wird, ist für den Sender der Botschaft völlig unerheblich. Der Sender vertraut darauf, dass der Fernseher die Botschaft "Einschalten" versteht und korrekt ausführt. Die komplexe Implementierung in dem Empfänger ist gekapselt.
Stärkung der Abstraktion
Das Senden von Botschaften erlaubt es uns, mit Objekten auf einer höheren, abstrakteren Ebene zu interagieren. Wir konzentrieren uns auf das Verhalten des Objekts (beschleunigen, changeSize) und nicht auf seine internen Daten (geschwindigkeit, diameter). Dies reduziert die Komplexität des Gesamtsystems erheblich, da man nicht jedes Detail jedes Objekts kennen muss, um es zu benutzen.
Entkopplung und Flexibilität
Da der Sender die interne Logik des Empfängers nicht kennt, sind die beiden Objekte Sender und Empfänger nur lose gekoppelt.
Der Vorteil dieser losen Kopplung ist, dass man die Implementierung der beschleunigen()-Methode im Auto-Objekt komplett ändern kann. Solange die Botschaft - also der Methodenname und die Parameter - gleich bleibt, muss der Quellcode des Senders - also der Quelltext der entsprechenden Sender-Klasse - nicht angepasst werden. Das macht Software viel einfacher zu warten und zu erweitern. Man spricht hier auch von einer "Trennung der Schnittstelle von der Implementierung".
Unterstützung der Polymorphie
Diesen Vorteil können wir uns wieder an dem bewährten Shapes-Projekt mit seinen Circle-, Square- und Triangle-Objekten klarmachen. Egal, ob wir ein Circle-Objekt sonne, ein Square-Objekt haus oder ein Triangle-Objekt dach haben, kann man an jedes dieser drei Objekte die gleiche Botschaft schicken, zum Beispiel changeColor("yellow") oder moveHorizontal(120).
Der Sender muss nicht wissen, welchen konkreten Objekttyp er vor sich hat. Er sendet einfach die Botschaft und kann darauf vertrauen, dass der Empfänger die Botschaft versteht und schon wissen wird, wie er diese umsetzt.
Am Beispiel einer heterogenen ArrayList könnte man diesen Aspekt gut verdeutlichen. Stellen Sie sich eine ArrayList mit Objekten der Oberklasse GeoFigure vor. Von dieser Oberklasse gibt es nun Unterklassen wie Circle, Square, Rectangle, Triangle und so weiter. In der ArrayList sind nun 20 Objekte gespeichert, und zwar Objekte von allen Unterklassen von GeoFigure. Wenn in der Oberklasse eine Methode changeColor() definiert wurde, besitzen auch alle Objekte der Unterklassen diese Methode. Das heißt, der Sender (beispielsweise eine Klasse Zeichnung) kann nun an jedes Element der ArrayList die Botschaft changeColor("blue") senden, egal ob das jeweilige Objekt der Klasse Circle, der Klasse Square oder einer anderen Unterklasse von GeoFigure angehört.
Quellen:
- Lahres et al.: Objektorientierte Programmierung, Rheinwerk Computing 2021.
- Barnes, Kölling: Java lernen mit BlueJ - Objects first. Pearson-Verlag 2019.
- Ullenboom: Java ist auch eine Insel, Rheinwerk Computing 2023.
- Martin: Clean Code - A Handbook of Agile Software Craftmanship, Pearson Education 2009
- Balzert: Objektorientiert Programmieren, 4. Auflage, Springer-Verlag Berlin 2025.