Grundlagen der Programmierung: Entwurfsmuster

Iterator: Problem und Lösung

Testen Sie unsere 1920 Kurse

10 Tage kostenlos!

Jetzt testen Alle Abonnements anzeigen
Auf die Einzelteile eines Objektes zuzugreifen, ohne etwas über den Aufbau des Objekts zu wissen, ist schwierig. Hier erfahren Sie, worin das Problem besteht und wie die Lösung aussieht, die der "Iterator" anbietet.
05:05

Transkript

Dieses Entwurfsmuster haben die meisten von Ihnen wahrscheinlich schon angewendet und einige vielleicht sogar ohne zu wissen, dass es überhaupt ein Muster ist. Die Rede ist vom Iterator. Es geht dabei um folgendes. In jeder größeren Anwendung arbeiten wir mit Sammlungen von Objekten, also mit Listen, mit Mengen und Ähnlichem. Diese haben häufig einen recht unterschiedlichen internen Aufbau und auch der Zugriff auf die einzelnen Elemente erfolgt häufig in einer unterschiedlichen Art und Weise. Nun möchten wir gerne erreichen, dass ein Client auf alle Elemente einer solchen Sammlung zugreifen können soll, immer schön eins nach dem anderen ohne dabei wissen zu müssen, mit welcher konkreten Art von Datenstruktur er gerade kommuniziert. Insbesondere soll er also den unterschiedlichen internen Aufbau und den unterschiedlichen Elementzugriff nicht wirklich kennen müssen. Das klassische Beispiel für solche Datenstrukturen in der Java Welt ist natürlich das Java Collections Framework. In diesem Teil der Java Standardbibliothek findet sich eine Vielzahl unterschiedlichster Datenstrukturen, wie Lists, Sets, Maps oder Queues. Auch wenn wir zum Beispiel mit den Dateien in einem Verzeichnisbaum arbeiten möchten, dann stehen wir vor dem Problem, dass wir den Aufbau eines solchen Baumes ziemlich genau kennen müssen, um auf die einzelnen Elemente zugreifen zu können. Ganz allgemein haben wir dieses Problem eigentlich immer, wenn wir mit Mengen von Objekten arbeiten möchten und die Größe und die Struktur dieser Objektmengen oder auch beides dem Client eigentlich erst mal unbekannt sind. Schauen wir uns dieses Problem genauer an. Ich habe hier Datenstrukturen mit einem unterschiedlichen Aufbau zusammengestellt. Wir haben hier einen Baum, der aus Knoten und Blättern besteht. Wir haben hier eine Liste, auf deren Elemente ich über einen Index zugreifen kann und dann haben wir hier noch eine Map, die aus Paaren von Schlüsseln und Werten besteht. Also quasi eine Tabelle mit zwei Spalten und über die Elemente der ersten Spalte kann ich auf die Elemente der zweiten Spalte zugreifen. In der ersten Spalte könnte also beispielsweise eine Kundennummer stehen und in der zweiten Spalte dann das dazugehörige Kundenobjekt. Ein Client, der nun einfach nur nacheinander auf alle Elemente dieser Datenstruktur zugreifen möchte, muss dafür sehr genau wissen, wie diese Datenstrukturen aufgebaut sind und wie der Zugriff aussehen muss. Wenn wir jetzt eine weitere, eine vierte Datenstruktur hinzufügen wollen würden, die wieder anders aussieht, dann müssten wir auch den Client entsprechend erweitern, damit er auch mit dieser Datenstruktur arbeiten kann. Je mehr verschiedene Datenstrukturen wir also haben, desto größer und klobiger wird damit auch der Client. Wie sieht nun die Lösung aus, die auch im Java Collections Framework verwendet wird? Die Idee ist folgende. Wir kapseln das Wissen, das notwendig ist, um auf eine bestimmte Datenstruktur zugreifen zu können, in einem separaten Objekt und das ist dann der Iterator. Für die Baumstruktur gibt es also zum Beispiel den BaumIterator, der sehr genau weiß, wie er an die Knoten und an die Blätter rankommen kann. Für die Liste ist es dann der ListenIterator. Der kennt das Konzept Index und weiß, wie er es nutzen kann, um an die Elemente der Liste heranzukommen und für unsere zweispaltige Tabelle haben wir den TabellenIterator. Diese Iteratorobjekte kapseln also das Wissen, das notwendig ist, um auf die Elemente der jeweiligen Datenstrukturen zugreifen zu können. Das würde das Problem erst mal nur verlagern. Der Client müsste jetzt zwar nicht mehr wissen, wie er mit den Datenstrukturen kommunizieren muss, sieht sich nun aber verschiedenen Iteratorobjekten gegenüber. Um ihn auch davon noch zu entkoppeln, fügen wir eine Schnittstelle ein, die Schnittstelle Iterator. Alle drei Iteratorobjekte bieten nun diese gemeinsame Schnittstelle an und dadurch kann nun der Client mit allen dreien reden auf die gleiche Weise ohne wissen zu müssen, mit welchem Iteratorobjekt, mit welchem konkreten Iteratorobjekt er nun tatsächlich gerade kommuniziert. Dem Client werden dafür im Wesentlichen zwei Methoden angeboten, nämlich hasNext und next. Mit der Methode hasNext kann der Client den Iterator fragen, ob es noch weitere Elemente gibt oder ob wir schon durch sind und falls die Antwort positiv ist, das heißt also hasNext liefert true zurück, es gibt also noch weitere Elemente, kann sich der Client das nächste Element holen, indem er next aufruft. Nun hat der Client also die Möglichkeit auf verschiedenartige Datenstrukturen auf die gleiche Weise zuzugreifen und sich der Reihe nach jeweils alle Elemente holen zu können. Wenn Sie sich das nun genauer anschauen, dann werden Sie sehen, dass das Problem noch nicht komplett gelöst ist. Woher bekommt der Client das passende Iteratorobjekt, wenn er noch gar nicht wissen soll, um was für eine Datenstruktur es sich gerade handelt? Denn der Iterator, mit dem der Client reden möchte, muss zur jeweiligen Datenstruktur passen. Damit kommen wir zur anderen Hälfte der Lösung. Wir müssen dem Client jetzt eine einheitliche Möglichkeit bieten, wie er von den verschiedensten Datenstrukturen einen Iterator anfordern kann. Wie machen wir das? Wir definieren eine Schnittstelle. Diese Schnittstelle heißt Iterable, also interierbar und wird von den Datenstrukturen selbst implementiert. Diese Schnittstelle definiert eine einzige Methode, nämlich iterator und diese Methode iterator gibt nun einen Iterator zurück. Solange eine Datenstruktur also diese Schnittstelle anbietet, kann der Client zu der Datenstruktur hingehen und kann sagen, gib mir dein Iteratorobjekt und dafür muss er nicht wissen, um was für eine Art von Datenstruktur es sich tatsächlich handelt. Ist es ein Baum, bekommt er den BaumIterator. Ist es eine Liste, bekommt er den ListenIterator und ist es unsere Tabelle, bekommt er den TabellenIterator. Diese Objekte kann er dann verwenden, wie wir das gerade gesehen haben. Nun ist der Client also tatsächlich unabhängig. Er muss sich nicht mehr darum kümmern, wie er an die einzelnen Elemente herankommt und kann sich darauf konzentrieren, was er mit diesen Elementen tun soll.

Grundlagen der Programmierung: Entwurfsmuster

Erhalten Sie einen fundierten Einstieg in das Thema Entwurfsmuster (Design Patterns) und erfahren Sie, wie Sie Entwurfsmuster in objektorientierten Programmiersprechen umsetzen.

2 Std. 49 min (33 Videos)
Derzeit sind keine Feedbacks vorhanden...
 

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!