Iterator

Przeznaczenie

  • Iterator stosujemy tam, gdzie potrzebujemy jednolitego sposobu sekwencyjnego przeglądania elementów w zagregowanych obiektach

Kontekst

  • Istnieje agregat, który powinien być przeglądany w sposób sekwencyjny

Problem

  • Chcemy zapewnić sekwencyjny dostęp do agregatu bez ujawniania jego struktury wewnętrznej

Zastosowanie

Wzorca Iterator należy używać, gdy:

  • Uzyskanie dostępu do zawartości obiektu-agregatu bez ujawniania jego struktury wewnętrznej

  • Umożliwienie wielokrotnego przechodzenia obiektów-agregatów

  • Zapewnienie jednakowego interfejsu przechodzenia różnych struktur zagregowanych – umożliwienie iteracji polimorficznej

Struktura

_images/Iterator.png

Uczestnicy

Iterator – definiuje interfejs dostępu do elementów i przechodzenia ich

ConcreteIterator

  • implementuje interfejs iteratora

  • pamięta bieżącą pozycję osiągniętą przy przechodzeniu agregatu

Aggregate – definiuje interfejs tworzenia obiektów-iteratorów

ConcreteAggregate – implementuje interfejs tworzenia Iteratora tak, by przekazywał egzemplarz odpowiedniego iteratora konkretnego (ConcreteIterator)

Współpraca

Klasa ConcreteIterator śledzi, który obiekt w agregacie jest bieżący, i potrafi wskazać następny obiekt.

Konsekwencje

  1. Możliwość rozmaitego przechodzenia agregatów. Iteratory ułatwiają zmianę algorytmu przechodzenia (np. preorder, inorder). Wystarczy zastąpić jeden egzemplarz iteratora innym. Można też definiować podklasy Iteratora, aby uwzględnić nowe sposoby przechodzenia.

  2. Iteratory upraszczają interfejs agregatu (Aggregate). Interfejs przechodzenia zawarty w klasie Iterator eliminuje potrzebę istnienia podobnego interfejsu w agregacie.

  3. W danej chwili może się odbywać więcej niż jedno przechodzenie agregatu. Iterator śledzi na bieżąco swój stan związany z przechodzeniem.

Implementacja

  1. Który z uczestników steruje procesem iteracyjnym?

  • Klient – iterator zewnętrzny, bardziej elastyczny. Klienci muszą sami dbać o posuwanie naprzód przechodzenia i żądać od iteratora podania następnego elementu.

  • Iterator – iterator wewnętrzny. Klienci przekazują tylko operację wykonania, a iterator już sam wywołuje ją dla każdego elementu agregatu.

  1. Dodatkowe operacje iteratora.

  2. Stosowanie operatorów polimorficznych w C++. Obiekt-iterator jest dynamicznie przydzielany przez metodę wytwórczą. Jeśli polimorfizm nie jest potrzebny, lepiej używać iteratorów konkretnych, które mogą być umieszczane na stosie. Za usuwanie operatorów polimorficznych odpowiedzialny jest klient.

  3. Iteratory mogą mieć uprzywilejowany dostęp. Iterator można traktować jako rozszerzenia agregatu, który go stworzył. W C++ można wyrazić ten związek przez uczynienie iteratora przyjacielem jego agregatu (za pomocą deklaracji friend).

Wzorce pokrewne

Composite – iteratory stosuje się często do struktur rekurencyjnych, takich jak kompozyty (Composite). Factory Method – iteratory polimorficzne wykorzystują metody wytwórcze do tworzenia egzemplarzy odpowiednich podklas klasy Iterator.

Podsumowanie

  1. Zapewnia sekwencyjny dostęp do elementów obiektu zagregowanego bez ujawniania jego reprezentacji.

  2. Wylicza elementy agregatu i hermetyzuje te operacje w osobnym obiekcie.

Iterator zapewnia wspólny interfejs przeglądania elementów agregatu, umożliwiając korzystanie z polimorfizmu przy pisaniu kodu, który korzysta z tych elementów.