Design Pattern - Iterator

해당 포스팅은 Java 언어로 배우는 디자인 패턴 입문 책을 참고해 작성했습니다.
사용된 코드는 jongmin92/Design-Pattern repository 에서 확인할 수 있습니다.

Iterator 패턴

Java 언어에서 배열 arr의 모든 요소를 표시하기 위해서는 다음과 같이 for문을 사용합니다.

1
2
3
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

for문의 i++에서 i를 하나씩 증가시키면서 배열 arr의 요소 전체를 처음부터 차례대로 검색하게 됩니다. 여기서 사용되고 있는 변수 i의 기능을 추상화해서 일반화한 것을 디자인 패턴에서는 Iterator 패턴이라고 합니다.

Iterator 패턴이란, 무엇인가 많이 모여있는 것들을 순서대로 지정하면서 전체를 검색하는 처리를 실행하기 위한 것입니다. Iterator는 무엇인가를 ‘반복한다’라는 의미이며, 반복자라고도 합니다.

예제 프로그램

Iterator 패턴을 사용해 책장에 꽂혀 있는 책들을 하나씩 검색해 책 이름을 출력해보는 예제 프로그램을 작성해 보겠습니다.

Aggregate 인터페이스

Aggregate 인터페이스는 요소들이 나열되어 있는 ‘집합체’를 나타냅니다. 이 인터페이스를 구현하고 있는 클래스는 배열과 같이 무엇인가가 많이 모여 있습니다.

1
2
3
public interface Aggregate {
Iterator iterator();
}

Aggregate 인터페이스에 선언되어 있는 메소드는 iterator 메소드 하나뿐입니다. 이 메소드는 집합체에 대응하는 Iterator를 1개 작성하기 위한 것입니다.

Iterator 인터페이스

Iterator 인터페이스는 요소를 하나씩 나열하면서 루프 변수와 같은 역할을 수행합니다.

1
2
3
4
public interface Iterator() {
boolean hasNext();
Object next();
}

hasNext 메소드는 다음 요소가 존재하는지를 조사하기 위한 메소드입니다. 다음 요소가 존재하면 true를 반환하고, 다음 요소가 존재하지 않는 마지막 요소라면 false를 반환합니다. 즉, hasNext는 루프의 종료 조건으로 사용됩니다.

next 메소드는 집합체의 요소를 1개 반환합니다. 또한 next 메소드를 호출했을 때 다음 요소를 반환하도록 내부 상태를 다음으로 진행시켜 두는 역할도 함께합니다.

Book 클래스

Book 클래스는 책을 나타내는 클래스입니다.

1
2
3
4
5
6
7
8
9
10
11
public class Book {
private String name;

public Book(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

BookShelf 클래스

BookShelf 클래스는 책장을 나타내는 클래스입니다. 이 클래스를 집합체로 다루기 위해 Aggregate 인터페이스를 구현합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BookShelf implements Aggregate {
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 iterator() {
return new BookShelfIterator(this);
}
}

iterator 메소드는 BookShelf 클래스에 대응하는 Iterator로서, BookShelfIterator라는 클래스의 인스턴스를 생성해서 그것을 반환합니다.

BookShelfIterator 클래스

BookshelfIterator 를 Iterator로서 다루기 위해 Iterator 인터페이스를 구현합니다. bookShelf 필드는 BookShelfIterator가 검색할 책장이고, index 필드는 현재 가리키는 책을 가리키는 첨자입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;

public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}

@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}

@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}

Main 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Effective Java"));
bookShelf.appendBook(new Book("Head First Java"));
bookShelf.appendBook(new Book("Thinking In Java"));
bookShelf.appendBook(new Book("Agile Java"));

Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.println(book.getName());
}
}
}
1
2
3
4
5
// 실행결과
Effective Java
Head First Java
Thinking In Java
Agile Java

Iterator 패턴의 구성요소

  • Iterator(반복자)의 역할
    요소를 순서대로 검색해가는 인터페이스(API)를 결정 (hasNext, next)

  • ConcreteIterator(구체적인 반복자)의 역할
    Iterator가 결정한 인터페이스(API)를 실제로 구현

  • Aggregate(집합체)의 역할
    Iterator 역할을 만들어내는 인터페이스(API)를 결정

  • ConcreteAggregate(구체적인 집합체)의 역할
    Aggregate 역할이 결정한 인터페이스(API)를 실제로 구현

사고 넓히기

구현에 상관 없이 Iterator를 사용할 수 있다.

1
2
3
4
while (it.hasNext()) {
Book book = (Book) it.next();
System.out.println(book.getName());
}

여기서 사용되고 있는 것은 hasNext와 next라는 Iterator의 메소드 뿐입니다. BooShelf의 구현에서 사용되고 있는 메소드는 호출되고 있지 않습니다. 결국 위 코드의 while 루프는 BookShelf의 구현에 의존하지 않습니다.

그렇기 때문에 현재 배열을 사용해 구현하고 있는 BookShelf를 List를 사용하도록 수정해도, 위의 while 루프는 전혀 변경하지 않아도 동작합니다.

Aggregate와 Iterator의 대응

BookShelfIterator는 BookShelf가 어떻게 구현되고 있는지 알기 때문에, ‘다음 책’을 얻기 위해 getBookAt 메소드를 호출할 수 있었습니다.

만약 BookShelf의 구현을 전부 변경하고, getBookAt 메소드라는 인터페이스(API)도 변경된다면 BookShelfIterator의 수정이 필요하게 됩니다.

Author

KimJongMin

Posted on

2018-08-18

Updated on

2021-03-22

Licensed under

댓글