이터레이터 패턴
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 76번째.
반복자 패턴(Iterator Pattern)은 컬렉션의 내부 구조를 노출하지 않고 요소들에 순차적으로 접근할 수 있는 방법을 제공하는 행동 디자인 패턴입니다. 배열, 연결 리스트, 또는 트리 중 무엇을 사용하든, 반복자는 요소들을 순회하는 일관된 방식을 제공합니다.
이 패턴은 순회 로직을 컬렉션 자체에서 분리합니다. 여기에는 두 가지 주요 구성 요소가 포함됩니다: 요소를 순회하기 위한 메서드를 정의하는 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++];
}
}
}이터레이터는 자신의 순회 상태를 유지하므로, 여러 이터레이터가 동일한 컬렉션을 독립적으로 순회할 수 있습니다. 클라이언트는 컬렉션이 데이터를 어떻게 저장하는지 알지 못해도 이터레이터를 사용합니다:
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의 내장된 Iterable 및 Iterator 인터페이스는 이 정확한 패턴을 따르며, 이것이 Iterable을 구현하는 모든 클래스에서 향상된 for 루프(enhanced for-loops)를 사용할 수 있는 이유입니다. 이터레이터 패턴(Iterator Pattern)은 여러 순회 방법을 제공해야 하거나 클라이언트 코드로부터 복잡한 내부 구조를 숨겨야 할 때 필수적입니다.
챌린지
쉬움Iterator 패턴을 사용하여 플레이리스트 시스템을 구축해 봅시다! 노래를 저장하고 내부 저장 방식은 노출하지 않으면서 순차적으로 탐색할 수 있는 커스텀 반복자(iterator)를 제공하는 음악 플레이리스트를 만들 것입니다. 이는 Iterator 패턴의 완벽한 활용 사례로, 사용자가 깔끔하고 통일된 인터페이스를 통해 컬렉션을 탐색할 수 있게 해줍니다.
코드는 네 개의 파일로 구성됩니다:
Iterator.java: 두 개의 메서드를 가진 제네릭Iterator<T>인터페이스를 정의합니다: 더 많은 요소가 있는지 여부를 나타내는 불리언 값을 반환하는hasNext()와, T 타입의 다음 요소를 반환하는next()입니다.Playlist.java: 노래들을 담는 집합체(aggregate) 클래스를 생성합니다.Playlist는 생성자에 전달된 고정된 용량의 String 배열에 노래를 저장하고, 추가된 노래의 개수를 추적해야 합니다. 플레이리스트에 노래를 추가하기 위한addSong(String song)메서드를 포함하세요.Playlist에는
Iterator<String>를 반환하는createIterator()메서드가 필요합니다. Iterator 인터페이스를 구현하는PlaylistIterator라는 프라이빗 내부 클래스를 만들어 이를 구현하세요. 이 내부 반복자는 자신의 인덱스 위치를 유지하며 노래 배열을 탐색하여 각 노래를 순서대로 반환합니다.Song.java: 노래 제목을 감싸는 간단한Song클래스를 생성합니다. 제목(String)을 받는 생성자,getTitle()메서드, 그리고"Playing: " + title을 반환하는toString()메서드가 있어야 합니다.Main.java: 반복자 시스템을 하나로 합칩니다! 하나의 입력을 받게 됩니다: 쉼표로 구분된 노래 제목 목록입니다 (예:Bohemian Rhapsody,Stairway to Heaven,Hotel California).노래 10개를 담을 수 있는 용량의 Playlist를 생성하세요. 입력을 파싱하여 각 노래 제목을 플레이리스트에 추가합니다. 그런 다음 플레이리스트에서 반복자를 얻어 모든 노래를 탐색하며, 각 노래를 Song 객체로 감싸서 출력합니다 (출력 시
Playing: [title]형식으로 표시됩니다).모든 노래를 반복한 후, 새 줄에
Playlist complete!를 출력하세요.
하나의 입력을 받습니다: 쉼표로 구분된 노래 제목 문자열입니다.
예를 들어, 입력이 Yesterday,Imagine,Let It Be인 경우, 출력은 다음과 같습니다:
Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!Main 클래스가 내부 배열 구조에 대해 전혀 알지 못한 채 반복자의 hasNext()와 next() 메서드를 사용하여 플레이리스트를 탐색하는 방식에 주목하세요. 반복자는 모든 탐색 로직을 캡슐화하여 컬렉션의 내부 표현을 클라이언트 코드로부터 숨깁니다!
직접 해보기
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에서 반복자(iterator)를 가져오기
// TODO: 반복자를 사용하여 모든 노래를 순회
// 각 노래에 대해, Song 객체로 감싸고 출력
// TODO: 모든 노래를 순회한 후 "Playlist complete!" 출력
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조