Pattern - Iterator

3 minute read

공자께서 말씀하였다. “남이 자신을 알아주지 못함을 걱정하지 말고, 내가 남을 알지 못함을 걱정해야 한다. “

의도


내부 표현부를 노출하지 않고 어떤 집합 객체에 속한 원소들을 순차적으로 접근할 수 있는 방법을 제공합니다.

동기


  • 리스트 등 집합 객체들은 이 내부 표현 구조를 노출하지 않고도 자신의 원소를 접근할 수 있는 방법을 제공하는게 좋습니다. 여기에 덧붙여서, 이미 정의한 방법과 다른 방법으로 이들 원소들을 순회하고자 할 수도 있습니다. 그러나 다른 순회 방법이 바뀌었다고 List 클래스의 인터페이스를 부풀리고 싶지는 않을 것입니다. 또한 동일한 리스트에 대해서 하나 이상의 순회 방법을 정의하고 싶을 때도 있습니다.
  • 이런 문제를 해결하는데 사용하는 것이 바로 반복자 패턴입니다. 이 패턴의 주요 골자는 리스트 객체에 접근해서 새로운 내용을 삽입,삭제하거나 순회하는 내용을 반복자 객체에 정의하는 것입니다. 반복자 객체를 나타내는 Iterator 클래스는 리스트의 원소들에 접근하는데 필요한 인터페이스를 제공합니다. 즉, Iterator 객체는 현재 원소가 무엇인지 관리하고, 이미 방문한 원소들이 무엇인지 알고 있습니다.
  • Iterator 클래스와 List 클래스가 한 쌍으로 묶여있기 때문에 , 사용자는 어떤 집합 구조에 대해서 순회할 주제가 리스트 인지를 알아야 한다는 점에서 주목하라. 따라서 사용자는 반드시 특정한 집합 구조에 따라가야 합니다. 이대, List의 복합 구조를 변경하더라도 사용자 코드는 변경하지 않도록 만들면 더욱 좋습니다. 이렇게 하려면, 반복자의 개념을 일반화하여 다형성을 지닌 반복이 가능하도록 하면 됩니다.

활용성


  • 객체의 내부 표현 방식은 모르고도 집합 객체의 각 원소들에 접근하고 싶을 때
  • 집합 객체를 순회하는 다양한 방법을 지원하고 싶을 때,
  • 서로 다른 집합 객체 구조에 대해서도 동일한 방법으로 순회하고 싶을 때

항목에 대한 설명


  • Iterator 원소를 접근하고 순회하는 데 필요한 인터페이스를 제공합니다.

  • Concrete Iterator Iterator 에 정의된 인터페이스를 구현하는 클래스로, 순회 과정 중 집합 객체 내에서 현재 위치를 기억합니다.

  • Aggregate Iterator 객체를 생성하는 인터페이스를 정의합니다.

  • Concrete Aggregate 해당하는 Concrete Iterator 의 인스턴스를 반환하는 Iterator 생성 인터페이스를 구현합니다.

  • Client

협력방법


ConcreteIterator는 집합 객체 내 현재 객체를 계속 추적하고 다음번 방문할 객체를 결정합니다.

결과


  • 집합 객체의 다양한 순회 방법을 제공합니다. 구조가 복잡한 집합 객체는 다양한 방법으로 순회할 수 있습니다. 이를 테면, 컴파일러에서 코드 생성 및 의미 점검을 진행하려면 파스 트리를 순회해야합니다. 코드를 생성하기 위해 트리를 순회할 때 중위 순회 방식이나 전위 순회 방식을 사용 할 수 있습니다. 이때 Iterator는 순회 방식을 바꿀 수 있도록 합니다. 즉, 새로운 순회 방법을 Iterator 서브 클래스로 정의하여 기존 순회 방법을 다른 순회 알고리즘 인스턴스로 완전히 교체하는 것입니다.
  • Iterator는 Aggregate 클래스의 인터페이스를 단순화 합니다. Iterator 의 순회 인터페이스는 Aggregate 클래스에 정의한 자신과 비슷한 인터페이스들을 없애서 Aggregate 인터페이스를 단순화할 수 있습니다.
  • 집합 객체에 따라 하나 이상의 순회 방법이 제공될 수 있습니다. 각 Iterator 마다 자신의 순회 상태가 있으므로 하나의 집합 객체를 한번에 여러 번 순회 시킬수 있습니다.

코드 예제 – 기본 샘플



package designpattern.gof_iterator.sample01;

public class IteratorMain {

    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Around the World in 80"));
        bookShelf.appendBook(new Book("Bible"));
        bookShelf.appendBook(new Book("Cinderella"));
        bookShelf.appendBook(new Book("Daddy-Long-Legs"));
        Iterator it = bookShelf.iterator();
        while (it.hasNext()) {
            Book book = (Book) it.next();
            System.out.println(book.getName());
        }
    }
}


package designpattern.gof_iterator.sample01;

public interface Iterator {

  public abstract boolean hasNext();

  public abstract Object next();
}
                                      
package designpattern.gof_iterator.sample01;

public class BookShelfIterator implements Iterator {

    private BookShelf bookShelf;

    private Book book;

    private int index;

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

    public boolean hasNext() {
        if (index < bookShelf.getLength()) {
            return true;
        } else {
            return false;
        }
    }

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

package designpattern.gof_iterator.sample01;

public interface Aggregate {
    public abstract Iterator iterator();
}


package designpattern.gof_iterator.sample01;

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

    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}

package designpattern.gof_iterator.sample01;

public class Book {
    private String name;

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

    public String getName() {
        return name;
    }
}