Menu
Coddy logo textTech

Wzorzec iteratora

Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 76 z 87.

Wzorzec iteratora to behawioralny wzorzec projektowy, który umożliwia sekwencyjny dostęp do elementów kolekcji bez ujawniania jej wewnętrznej struktury. Niezależnie od tego, czy pracujesz z tablicą, listą połączoną czy drzewem, iterator zapewnia jednolity sposób przechodzenia przez elementy.

Wzorzec oddziela logikę przechodzenia od samej kolekcji. Obejmuje dwa główne komponenty: interfejs Iterator, który definiuje metody przechodzenia przez elementy, oraz Iterable (lub Aggregate), który tworzy iteratory dla swojej kolekcji:

interface Iterator<T> {
    boolean hasNext();
    T next();
}

interface Container<T> {
    Iterator<T> createIterator();
}

class BookShelf implements Container<String> {
    private String[] books;
    private int count = 0;
    
    public BookShelf(int size) {
        books = new String[size];
    }
    
    public void addBook(String book) {
        books[count++] = book;
    }
    
    public Iterator<String> createIterator() {
        return new BookIterator();
    }
    
    private class BookIterator implements Iterator<String> {
        private int index = 0;
        
        public boolean hasNext() {
            return index < count;
        }
        
        public String next() {
            return books[index++];
        }
    }
}

Iterator przechowuje własny stan przechodzenia, umożliwiając wielu iteratorom niezależne przechodzenie po tej samej kolekcji. Klienci korzystają z iteratora, nie wiedząc, w jaki sposób kolekcja przechowuje dane:

BookShelf shelf = new BookShelf(3);
shelf.addBook("Design Patterns");
shelf.addBook("Clean Code");

Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

Wbudowane interfejsy Java Iterable i Iterator są zgodne z tym dokładnym wzorcem, dlatego możesz używać rozszerzonych pętli for z każdą klasą implementującą Iterable. Wzorzec iteratora jest niezbędny, gdy potrzebujesz udostępnić wiele metod przechodzenia po elementach lub ukryć złożone struktury wewnętrzne przed kodem klienta.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system playlisty z użyciem wzorca Iteratora! Utworzysz playlistę muzyczną, która przechowuje utwory i udostępnia własny iterator pozwalający przechodzić przez nie kolejno, bez ujawniania sposobu ich wewnętrznego przechowywania. To idealne zastosowanie wzorca Iteratora, który pozwala użytkownikom przeglądać Twoją kolekcję za pomocą przejrzystego, jednolitego interfejsu.

Podzielisz swój kod na cztery pliki:

  • Iterator.java: Zdefiniuj generyczny interfejs Iterator<T> z dwiema metodami: hasNext(), która zwraca wartość logiczną informującą, czy są jeszcze jakieś elementy, oraz next(), która zwraca następny element typu T.
  • Playlist.java: Utwórz klasę agregującą, która przechowuje utwory. Twoja klasa Playlist powinna przechowywać utwory w tablicy String o stałej pojemności (przekazywanej do konstruktora) i śledzić, ile utworów dodano. Dodaj metodę addSong(String song), aby dodawać utwory do playlisty.

    Twoja klasa Playlist potrzebuje metody createIterator(), która zwraca Iterator<String>. Zaimplementuj ją, tworząc prywatną klasę wewnętrzną o nazwie PlaylistIterator, która implementuje Twój interfejs Iterator. Ten iterator wewnętrzny przechowuje własną pozycję indeksu i przechodzi przez tablicę utworów, zwracając każdy utwór po kolei.

  • Song.java: Utwórz prostą klasę Song, która przechowuje tytuł utworu. Powinna mieć konstruktor przyjmujący tytuł (String), metodę getTitle() oraz metodę toString(), która zwraca Playing: [title].
  • Main.java: Połącz swój system iteratora! Otrzymasz jedno wejście: listę tytułów utworów rozdzielonych przecinkami (na przykład: Bohemian Rhapsody,Stairway to Heaven,Hotel California).

    Utwórz Playlist o pojemności 10 utworów. Przetwórz dane wejściowe i dodaj każdy tytuł utworu do playlisty. Następnie pobierz iterator z playlisty i użyj go, aby przejść przez wszystkie utwory, wypisując każdy opakowany w obiekt Song (który wyświetli się jako Playing: [title]).

    Po przejściu przez wszystkie utwory wypisz Playlist complete! w nowej linii.

Otrzymasz jedno wejście: ciąg znaków zawierający tytuły utworów rozdzielone przecinkami.

Na przykład dla wejścia Yesterday,Imagine,Let It Be wynikiem będzie:

Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!

Zwróć uwagę, że Twoja klasa Main używa metod iteratora hasNext() i next(), aby przejść przez playlistę, nie wiedząc nic o strukturze bazowej tablicy. Iterator hermetyzuje całą logikę przechodzenia, ukrywając wewnętrzną reprezentację kolekcji przed kodem klienta!

Spróbuj swoich sił

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Utwórz Playlist o pojemności 10 utworów
        
        // TODO: Przetwórz dane wejściowe (rozdzielone przecinkami) i dodaj każdy tytuł utworu do listy odtwarzania
        
        // TODO: Pobierz iterator z listy odtwarzania za pomocą createIterator()
        
        // TODO: Użyj iteratora, aby przejść przez wszystkie utwory
        // Dla każdego utworu utwórz obiekt Song i go wypisz
        
        // TODO: Wypisz "Playlist complete!" po przejściu przez wszystkie utwory
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Java online