- Iterator 패턴 : 처리를 반복한다
Iterator 패턴은 컬렉션의 요소들의 기본 표현(리스트, 스택, 트리 등)을 노출하지 않고 그들을 하나씩 순회할 수 있으며, 무엇인가 많이 모여 있을 때 이를 순서대로 가리키며 전체를 검색하고 처리를 반복하는 패턴이다.
- 어떤 경우에 사용할까?
그냥 반복문을 돌리면 될텐데, 왜 번거롭게 Iterator라는 걸 만들어서 사용하는가?
가장 큰 이유는 Iterator를 사용함으로 구현과 분리하여 반복할 수 있다.
Iterator<Book> it = bookShelf.iterator();
while(it.hasNext()) {
Book book = it.next();
System.out.println(book.getName());
}
위의 while 문에서는 hasNext와 next라는 Iterator의 메서드만 사용되었으며, BookShelf 구현에 사용된 메서드는 호출되지 않았다. 즉, while 문은 BookShelf 구현에 의존하지 않았다.
디자인 패턴은 클래스 재사용을 촉진한다. 어떤 한 부품을 수정하더라도 다른 부품을 수정할 일이 적어진다는 의미다. 배열로 관리하던 BookShelf를 ArrayList로 수정한다 해도, 위의 while 문의 코드는 수정할 필요가 없다.
- 예제 코드
이름 | 설명 |
Iterable<E> | 집합체를 나타내는 인터페이스(java.lang 패키지) → 예제 프로그램에서는 Iterable<Book>으로 사용 |
Iterator<E> | 처리를 반복하는 반복자를 나타내는 인터페이스(java.util 패키지) → 예제 코드에서는 Iterator<Book>으로 사용 |
Book | 책을 나타내는 클래스 |
BookShelf | 책장을 나타내는 클래스 |
BookShelfIterator | 책장을 검색하는 클래스 |
Main | 동작 테스트용 클래스 |
- Iterable<E> 인터페이스(java.lang.Iterable)
public interface Iterable<E> {
public abstract Iterator<E> iterator();
}
- Iterator<E> 인터페이스(java.util.Iterator)
public interface Iterator<E> {
public abstract boolean hasNext();
public abstract E next();
}
- Book 클래스
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
- BookShelf 클래스
import java.util.Iterator;
public class BookShelf implements Iterable<Book> {
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public Book getBookAt(int index) {
return books[index];
}
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
public int getLength() {
return last;
}
@Override
public Iterator<Book> iterator() {
return new BookShelfIterator(this);
}
}
- BookShelfIterator 클래스
import java.util.Iterator;
import java.util.NoSuchElementException;
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
if(index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
@Override
public Book next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
- Main 클래스
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long-Legs"));
// 명시적으로 Iterator를 사용하는 방법
Iterator<Book> it = bookShelf.iterator();
while(it.hasNext()) {
Book book = it.next();
System.out.println(book.getName());
}
System.out.println();
// 확장 for문을 사용하는 방법
for(Book book : bookShelf) {
System.out.println(book.getName());
}
System.out.println();
}
}
참고문헌 : 유키 히로시 저/김성훈 역(2022), JAVA 언어로 배우는 디자인 패턴 입문, 영진닷컴
참고자료 : https://refactoring.guru/ko/design-patterns/iterator