Der Compound-Iterator für drei Iteratoren durchläuft quasi das kartesische Produkt dreier iterierbarer Folgen, also die Folge aller Tripel aus den Elementen dieser Folgen. Normalerweise benötigt man drei ineinander geschachtelte For-Schleifen, um die Elemente dieses kartesischen Produkts zu durchlaufen.
Ein Compound-Iterator hat dagegen den Vorteil, dass er, einmal geschrieben, nur eine For-Schleife benötigt und dass er überall einsetzbar ist, wo ein Iterator stehen kann, zum Beispiel als Basisiterator eines Filteriterators.
Es sollen alle Positionen eines 8×8-Spielbretts durchlaufen werden und dabei jeweils ein Spielzug mit einem der Spielsteine 0, ..., 3 ausprobiert werden. Ein Iterator hierfür verwendet einen Basisiterator für die Zeilen und einen Subiterator für die Spalten des Spielbretts sowie einen Subsubiterator für die vier Spielsteine, und er setzt dann aus dem jeweiligen Zeilenindex z, dem Spaltenindex s und dem Spielstein f einen Spielzug zusammen.
Die Klasse Move kapselt ein solches Tripel von Integer-Werten.
Gesucht ist nun ein Iterator, der alle Positionen des Spielbretts durchläuft und dabei die vier Spielsteine ausprobiert. Ein solcher Iterator lässt sich als Compound-Iterator3 realisieren. Ein Compound-Iterator3 benutzt einen Basisiterator (im Beispiel der Iterator für die Zeilen), einen Subiterator (im Beispiel der Iterator für die Spalten) und einen Subsubiterator (im Beispiel der Iterator für die Spielsteine). Ferner wird eine Funktion composeItems benötigt, um aus den drei Cursor-Objekten der drei Iteratoren ein Objekt zu machen, das mit next() zurückgegeben wird (im Beispiel ein Move-Objekt bestehend aus dem Zeilenindex, dem Spaltenindex und dem Spielstein).
Als Basisiterator, als Subiterator und als Subsubiterator wird jeweils ein Generator verwendet, der nacheinander die Zahlen von 0 bis n-1 liefert.
Der Basisiterator, der Subiterator, der Subsubiterator und die Funktion composeItems werden in einem sogenannten Behavior festgelegt, mit dem der Compound-Iterator arbeitet. Das folgende Behavior AllMoves ergibt einen Compound-Iterator3, der alle Positionen eines rows×cols-Spielbretts durchläuft und dabei alle figs möglichen Spielsteine ausprobiert. Im Konstruktor werden die Werte für rows, für cols und für figs übergeben. Es folgen dann die vier Methoden, die in der abstrakten Basisklasse CompoundIteratorBehavior3 festgelegt sind.
In der Methode baseIterator wird der Basisiterator spezifiziert, der die Zahlen von 0 bis rows-1 durchläuft, in der Methode subIterator der Subiterator, der die Zahlen von 0 bis cols-1 durchläuft, und in der Methode subsubIterator der Subsubiterator, der alle Spielsteine von 0 bis figs-1 durchläuft. Im Allgemeinen ist es möglich, dass der Subiterator vom Cursor-Objekt x0 des Basisiterators abhängig ist und der Subsubiterator von den Cursor-Objekten x0 und x1 des Basisiterators und des Subiterators, deswegen die Parameter, dies wird aber hier nicht benutzt. Die Methode composeItems setzt aus dem Cursor-Objekt x0 des Basisiterators, dem Cursor-Objekt x1 des Subiterators und dem Cursor-Objekt x2 des Subsubiterators einen Spielzug (x0,x1,x2) zusammen.
Die erwähnte Factory-Methode, die den fertigen Iterator zurückgibt, befindet sich in der Basisklasse CompoundIteratorBehavior3.
Die folgende Main-Funktion testet den Compound-Iterator3 mit dem Behavior AllMoves. Es werden alle Positionen eines 2×3-Spielbretts durchlaufen und jeweils 2 Spielsteine ausprobiert.
Die konkret benötigte Funktionalität eines Compound-Iterators für drei Iteratoren wird in einem Behavior (hier AllMoves) festgelegt. Dies geschieht durch Angabe eines Basisiterators, eines Subiterators, eines Subsubiterators und der Funktion composeItems.
Zugrunde gelegt werden dabei getestete Implementierungen der Klassen Compound-Iterator3 und Compound-IteratorBehavior3.
Für das angegebene sehr einfache Beispiel lohnt sich der Aufwand, einen Compound-Iterator zu benutzen, vielleicht nicht. Dadurch aber, dass der Compound-Iterator selbst das Iterator-Interface implementiert, kann er überall eingesetzt werden, wo ein Iterator stehen kann, also z.B. als Basisiterator in einem Filteriterator oder als Subiterator in einem anderen Compound-Iterator.
Weiter mit: [Implementierung CompoundIterator3] oder [up]