„Hallo Amigo! Heute hat Ellie dir vom Adapter-Muster erzählt.“

Die meisten Klassen, die sich auf E/A-Ströme beziehen, sind als Adapter implementiert. Sie wandeln entweder gleichwertige Interfaces um oder verbinden sie, angefangen vom Einfachen bis hin zum Komplexen.

„Sind InputStreamReader und BufferedReader auch Adapter? Zumindest sind sie den Adaptern in der Art und Weise, wie sie verwendet werden, sehr ähnlich: Nachdem ein Objekt erzeugt wurde, wird es an den Konstruktor einer anderen Klasse übergeben.“

„Ja, InputStreamReader wandelt das InputStream-Interface in das Reader-Interface um. BufferedReader ist kein Adapter in seiner reinsten Form, da die Entwickler von Java beschlossen haben, seinen Methoden kein eigenes, separates Interface zu geben. Aber die Verwandtschaft ist nicht zu leugnen.“

Anstatt Millionen verschiedener Klassen zu schreiben, haben die Java-Entwickler zwei Dutzend Adapter geschrieben und diesen erlaubt, sich so miteinander zu verbinden, wie es sich ein Programmierer wünscht.

Dieses Konzept ist sehr praktisch. Ein Programmierer kann immer seine Klasse bzw. seinen Adapter schreiben, ihn ein Standard-Interface implementieren lassen und ihn in die Kette von Adapterobjekten, die er entwickelt hat, aufnehmen.

„So funktioniert das also alles. Statt großer komplexer Klassen bilden wir Ketten aus einfachen Objekten und Adaptern. Und dann erstellt man sie einfach und kombiniert sie in der richtigen Reihenfolge!“

„Und du implementierst das, was noch fehlt.“

„Ja, alles klar.“

„Aber eigentlich wollte ich dir heute von Reader und Writer erzählen. Das sind zwei abstrakte Klassen, die den Klassen InputStream und OutputStream sehr ähnlich sind. Aber im Gegensatz zu diesen Klassen arbeiten diese beiden Klassen mit Zeichen. Sie lesen und schreiben Zeichen. Sie sind sehr praktisch für die Arbeit mit Texten. Sehen wir uns ihre Methoden einmal an:“

Reader-Methoden Das tut die Methode
int read(char[] cbuf);
„Diese Methode liest sofort mehrere Zeichen in den Puffer (char-Array), bis der Puffer voll ist oder bis die Quelle keine Zeichen mehr zum Lesen hat.
Die Methode gibt die Anzahl der tatsächlich gelesenen Zeichen zurück (die kleiner als die Länge des Arrays sein kann)
int read();
„Diese Methode liest ein Zeichen und gibt es zurück. Das Ergebnis wird zu einem int erweitert. Wenn keine Zeichen vorhanden sind, gibt die Methode -1 zurück.“
boolean ready();
Diese Methode gibt true zurück, wenn es ungelesene Zeichen für die read-Methoden gibt.
void close();
Diese Methode „schließt“ den Datenstrom. Du rufst sie auf, wenn du die Arbeit mit dem Stream beendet hast.
Das Objekt führt dann die notwendigen Operationen aus, um die Datei zu schließen usw.
Zu diesem Zeitpunkt kannst du keine Daten mehr aus dem Stream lesen.

„Es zeigt sich, dass die read(char [] cbuf)-Methode des Reader es uns ermöglicht, ganze Blöcke von Zeichen zu lesen, anstatt nur ein Zeichen auf einmal. Das ist schneller und praktischer.“

„Exakt. Sehen wir uns jetzt mal an, welche Methoden Writer besitzt:“

Methode Das tut die Methode
void write(int c);
Diese Methode schreibt ein Zeichen. Der Typ int wird auf ein char eingeschränkt. Der zusätzliche Teil wird einfach verworfen.
void write(char[] cbuff);
Diese Methode schreibt ein Array von Zeichen.
void write(String s);
Diese Methode schreibt eine Zeichenkette. Sie wird einfach in eine Reihe von Zeichen umgewandelt und dann wird die zweite Methode aufgerufen.
void flush();
Wenn der Datenstrom intern noch nicht geschriebene Daten speichert, erzwingt diese Methode den Schreibvorgang.
void close();
Diese Methode „schließt“ den Datenstrom. Du rufst sie auf, wenn du die Arbeit mit dem Stream beendet hast.
Das Objekt führt dann die notwendigen Operationen aus, um die Datei zu schließen usw. Du kannst keine Daten mehr in den Stream schreiben, und flush wird automatisch aufgerufen.

Wichtig ist, dass Reader und Writer abstrakte Klassen sind. Sie tun nichts und enthalten praktisch keinen Code. Alle ihre Methoden müssen in den Klassen, die von ihnen erben, implementiert werden. Ihre Aufgabe ist es, die Interaktion der Klassen zu standardisieren. Die Entwickler müssen keine eigenen Standards für die Interaktion erfinden. Es ist viel bequemer für alle, ein paar grundlegende Standards aufzubauen. Dadurch können von unterschiedlichen Programmierern geschriebene Klassen nicht nur problemlos mit den von Javas Entwicklern geschriebenen Klassen interagieren, sondern auch mit den von anderen Programmierern geschriebenen Klassen.

Standards sind mächtig.

„Du sagst es. Die Unterstützung gemeinsamer Standards ist für alle Beteiligten von Vorteil.“