Grundlagen der Programmierung: Entwurfsmuster

Iterator: Umsetzung und Diskussion

Testen Sie unsere 1961 Kurse

10 Tage kostenlos!

Jetzt testen Alle Abonnements anzeigen
Sowohl die praktische Umsetzung des "Iterator"-Musters als auch die konkreten Vor- und Nachteile werden hier ausführlich erläutert.
06:47

Transkript

Das Entwurfsmuster Iterator ermöglicht es einem Client auf alle Elemente einer Datenstruktur der Reihe nach zugreifen zu können, ohne den internen Aufbau dieser Datenstruktur kennen zu müssen. Das dafür notwendige Wissen wird in den Iterator-Objekten gekapselt, die von den jeweiligen Datenstrukturen selbst zur Verfügung gestellt werden. Auch im Collections Framework der Java Standardbibliothek wird dieses Entwurfsmuster so eingesetzt. Ich zeige das hier in einer kurzen Demonstration. Ich habe ein kleines CollectionsDemo und hier haben wir ArrayList. Das ist zum Beispiel eine solche Datenstruktur. In diesem Fall ist es eine ArrayList für Strings. Ich kann hier also mehrere Strings hineinwerfen. Der typische Java-Weg auf alle Elemente einer Liste zuzugreifen, ist die erweiterte For-Schleife. Hier auf der rechten Seite steht der Name der Liste, also namen und auf der linken Seite haben wir eine Variable, die ein einzelnes Element der Liste aufnehmen kann. Auf diese Weise gehen wir also durch alle Elemente der Liste durch und geben die der Reihe nach aus. Anscheinend hat das alles überhaupt nichts mit dem Iterator zu tun. Wo kommt der da jetzt vor? Wenn wir hier diese Vorschleife haben, dann passiert unter der Haube eigentlich etwas mehr als das, was wir da sehen und das sieht dann ungefähr so aus und zwar gehen wir hier zuerst zu unserer Liste und rufen die Methode Iterator auf. Die liefert dann ein Objekt zurück, was das Interface Iterator implementiert und da wir dieses Iterator-Objekt von unserer Liste bekommen haben, ist es offensichtlich der Iterator, der durch Listen iterieren kann. Nun fragen wir den Iterator, ob es noch weitere Elemente gibt in der Liste. Wenn er ja sagt, dann gehen wir rein in die Schleife, holen uns mit next das nächste Element und geben das nächste Element aus. Dann gehen wir wieder hoch, fragen wieder, gibt es noch weitere und geben die wieder aus solange, bis es keine Elemente mehr gibt. Das heißt, unter der Haube wird hier sehr wohl der Iterator eingesetzt. Die obere Schreibweise der For-Schleife verbirgt das nur vor uns und macht den Quelltext so obendrein noch besser lesbar. So funktioniert das nun also mit den Klassen, die es in der Standardbibliothek bereits gibt. Wie sieht das nun aber aus, wenn wir eigene Datenstrukturen erstellen und die auch so bequem nutzen können möchten? Ich habe dazu eine einfache Datenstruktur vorbereitet als Beispiel und zwar eine einfache Liste. Die ist sehr simple gestrickt. Die hält ihre Daten in einem int Array vor und die Größe dieses Arrays muss ich angeben, wenn ich eine einfache Liste erzeuge. Jetzt kann man in diese Liste Werte hineinpacken, indem man den Wert und den entsprechenden Index angibt und man die Werte natürlich wieder rausholen auch durch Angabe des Index wieder. Schließlich kann ich diese einfache List noch fragen, wie groß sie denn insgesamt ist und das war es dann eigentlich auch schon. Erst mal noch nichts mit Iterator, einfach nur diese einfache Liste. Das Arbeiten mit dieser Liste sieht dann so aus. Ich baue mir hier eine Liste mit Platz für fünf Zahlen. Dann packe ich einen Index 0 die 17, einen Index 2 die 52 und Index 4 die 36. Die übrigen Elemente behalten also ihren Standardwert 0. Wenn ich nun auf alle Elemente der Reihe nach zugreifen möchte, dann muss ich dafür die klassische For-Schleife bemühen, da ich mir jedes einzelne Element über dessen Index herausholen muss. Das heißt, ich fange bei 0 an. Mache das solange, wie ich die Größe meiner Liste noch nicht erreicht habe. Zähle immer 1 hoch. Dann hole ich mir das entsprechende Element raus, merke mir das und zeige es an. Das funktioniert natürlich auch. Nun wollen wir dafür sorgen, dass wir unsere Liste auch in der komfortablen For-Schleife benutzen können. Dazu habe ich hier die aufgebohrte Variante unserer einfachen Liste. Die heißt dann Liste. Die Grundstruktur ist die gleiche, also auch das int Array, Konstruktor, schreiben, lesen, getGroesse. Neu hinzugekommen ist aber, dass die Liste die Schnittstelle Iterable implementiert aus dem package java.util und das bedeutet, dass ich jetzt eine zusätzliche Methode anbieten muss, nämlich die Methode iterator und die sollte einen Iterator zurückgeben. Da dieser Iterator nur mit einer solchen Liste zusammen funktioniert und auch eigentlich überhaupt nicht unabhängig von ihr erzeugt werden können soll, wird er hier als statische innere Klasse realisiert und diese Klasse ist obendrein private. Das ist jetzt unser eigentlicher Iterator, der ZahlenIterator, der über die Elemente der Liste drüberiterieren kann. Er implementiert die Schnittstelle Iterator und das heißt, dass er zwei Methoden liefen muss, nämlich hasNext und next. Damit er diese Aufgabe erfüllen kann, hat er zwei Attribute. In dem ersten Attribut merkt er sich, an welcher Position innerhalb der Liste er sich gerade befindet und im zweiten Attribut merkt er sich, um welche Liste es sich eigentlich handelt. Die Liste bekommt er im Konstruktor übergeben und die Position wird mit 0 initialisiert. In hasNext soll der Iterator mitteile, ob es noch weitere Elemente gibt. Dazu muss er also lediglich schauen, ob wir mit der Position schon am Ende der Liste angekommen sind. Die Methode next liefert nun das Element an der aktuellen Position, zählt die Position 1 hoch und gibt das gefundene Element zurück. Wenn wir nun von unserer Klasse Liste die Methode iterator aufrufen, dann bekommen wir eine Instanz dieses inneren Klasse ZahlenIterator und können diese dann benutzen, um über die Liste drüber zu gehen. Auch das möchte ich natürlich zeigen. Das sieht dann so aus. Das ist dieselbe Liste bzw. es ist eine Liste mit derselben Größe und denselben Elemente und nun können wir also zu dieser Liste hingehen, können uns den Iterator holen und mit diesem Iterator über die Liste drüberiterieren und wir können natürlich, was wir eigentlich erreichen wollten, die For-Schleife verwenden, die im Hintergrund den Iterator benutzt und so noch etwas für die Lesbarkeit und Verständlichkeit des Codes tun. Eine kleine Sache habe ich Ihnen noch unterschlagen. Das Interface Iterator aus der Standardbibliothek definiert nämlich nicht zwei Methoden hasNext und next sondern drei. Die dritte Methode heißt remove und soll eigentlich dazu dienen, dass der Iterator das Element an der aktuellen Position der Liste entfernt. Laut Spezifikation ist es aber eine optionale Operation. Das heißt, unser Iterator muss das nicht können und es ist ihm also erlaubt stattdessen eine UnsupportedOperationException zu werfen, was wir hiermit auch tun. Fassen wir kurz zusammen. Die Vorteile des Iterator-Musters sind der vereinfachte Zugriff für den Client auf unterschiedlichste Datenstrukturen über eine einheitliche Schnittstelle und die Entkopplung des Clients vom internen Aufbau dieser Datenstrukturen. Außerdem wird, wie wir gerade gesehen haben, der Client-Code obendrein noch besser lesbar. Als Nachteile muss man natürlich nenne, den Mehraufwand für das Erstellen der Iterator-Klassen. Diese sind eng an ihre jeweiligen Datenstrukturen gekoppelt und Änderungen am Aufbau dieser Datenstrukturen haben zwangsläufig auch Änderungen an den Interator-Klassen zur Folge und wenn Sie Anwendungen bauen, in denen mehrere Prozesse gleichzeitig auf dieselben Datenstrukturen zugreifen können sollen und vielleicht sogar dieselben Iteratoren benutzen, dann müssen Sie natürlich noch etwas mehr Aufwand treiben, um diese Multi-Thread-Fähigkeit auch abzusichern. Damit kennen Sie nun den Iterator ganz genau und wissen sogar, dass es sich dabei um ein Entwurfsmuster handelt.

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!