Menu
Coddy logo textTech

이터레이터 패턴

Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 87개 중 76번째.

Iterator 패턴은 기본 구조를 노출하지 않고 컬렉션의 요소에 순차적으로 접근하는 방법을 제공하는 행동 설계 패턴입니다. array, 연결 리스트 또는 트리로 작업하든, iterator는 요소를 순회할 수 있는 일관된 방법을 제공합니다.

이 패턴은 순회 로직을 컬렉션 자체와 분리합니다. 여기에는 두 가지 주요 구성 요소가 포함됩니다. 요소를 순회하기 위한 메서드를 정의하는 Iterator 인터페이스와, 해당 컬렉션에 대한 이터레이터를 생성하는 Iterable(또는 Aggregate)입니다.

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는 its 자체 순회 상태를 유지하므로, 여러 iterator가 동일한 컬렉션을 독립적으로 순회할 수 있습니다. 클라이언트는 컬렉션이 데이터를 어떻게 저장하는지 알 필요 없이 iterator를 사용합니다.

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());
}

Java의 내장 IterableIterator 인터페이스는 이와 정확히 같은 패턴을 따르므로, Iterable을 구현하는 모든 클래스에서 향상된 for 루프를 사용할 수 있습니다. 클라이언트 코드에 여러 순회 방법을 제공하거나 복잡한 내부 구조를 숨겨야 할 때 Iterator 패턴은 필수적입니다.

challenge icon

챌린지

쉬움

Iterator Pattern을 사용하여 플레이리스트 시스템을 만들어 봅시다! 노래를 저장하고, 노래가 내부적으로 어떻게 저장되는지는 노출하지 않으면서 노래를 순차적으로 탐색할 수 있는 사용자 지정 iterator를 제공하는 음악 플레이리스트를 만들게 됩니다. 이는 Iterator Pattern을 사용하기에 완벽한 사례로, 깔끔하고 일관된 interface를 통해 사용자가 컬렉션을 탐색할 수 있게 합니다.

코드를 네 개의 파일로 구성합니다.

  • Iterator.java: 두 개의 메서드를 가진 generic Iterator<T> interface를 Define합니다. 더 많은 요소가 exist하는지를 나타내는 boolean을 반환하는 hasNext()와 T 타입의 다음 요소를 반환하는 next()입니다.
  • Playlist.java: 노래를 holds하는 Aggregate class를 Create합니다. Playlist는 고정된 capacity의 String array에 노래를 저장해야 하며, constructor에 전달된 capacity를 사용하고, added된 노래의 수를 추적해야 합니다. 플레이리스트에 노래를 Add하는 addSong(String song) 메서드를 포함하세요.

    Playlist에는 Iterator<String>을 반환하는 createIterator() 메서드가 필요합니다. 이를 위해 PlaylistIterator라는 private inner class를 Create하고, 이 class가 여러분의 Iterator interface를 implements하도록 하세요. 이 inner iterator는 자체 index 위치를 유지하며 songs array를 탐색하고, 각 노래를 순서대로 반환합니다.

  • Song.java: 노래 제목을 감싸는 간단한 Song class를 Create합니다. 제목(String)을 받는 constructor, getTitle() 메서드, 그리고 Playing: [title]을 반환하는 toString() 메서드를 가져야 합니다.
  • Main.java: iterator 시스템을 하나로 결합합니다! 하나의 input으로 쉼표로 구분된 노래 제목 목록을 받습니다(예: Bohemian Rhapsody,Stairway to Heaven,Hotel California).

    capacity가 10곡인 Playlist를 Create합니다. input을 분석하고 각 노래 제목을 플레이리스트에 Add합니다. 그런 다음 플레이리스트에서 iterator를 가져와 모든 노래를 탐색하고, 각 노래를 Song 객체로 감싸서 출력합니다(이 객체는 Playing: [title]로 표시됩니다).

    모든 노래를 iterating한 후, 새 줄에 Playlist complete!를 출력합니다.

하나의 input으로 쉼표로 구분된 노래 제목 문자열을 받습니다.

예를 들어 input이 Yesterday,Imagine,Let It Be라면 출력은 다음과 같습니다.

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

Main class가 기본 array 구조에 대해 아무것도 알지 못한 채 iterator의 hasNext()next() 메서드를 사용하여 플레이리스트를 탐색하는 방식에 주목하세요. iterator가 모든 탐색 로직을 캡슐화하므로 컬렉션의 내부 표현이 client code에 노출되지 않습니다!

직접 해보기

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: 10개의 노래를 저장할 수 있는 용량의 Playlist 생성
        
        // TODO: 입력(쉼표로 구분됨)을 파싱하여 각 노래 제목을 playlist에 추가
        
        // TODO: createIterator()를 사용하여 playlist에서 이터레이터 가져오기
        
        // TODO: 이터레이터를 사용하여 모든 노래 순회
        // 각 노래를 Song 객체로 감싸서 출력
        
        // TODO: Print "Playlist complete!" after iterating through all songs
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Java 컴파일러